mirror of
https://github.com/sonr-io/sonr.git
synced 2026-08-02 17:31:39 +00:00
refactor/internal (#1216)
* refactor: update import paths in gateway handlers * refactor: remove obsolete devtools Makefile and README * build: optimize build process for improved efficiency * refactor: remove obsolete pkl files related to Matrix and Sonr network configurations * refactor: move embed code to x/dwn/types
This commit is contained in:
@@ -1,16 +0,0 @@
|
||||
---
|
||||
aliases: [README]
|
||||
tags: []
|
||||
title: README
|
||||
linter-yaml-title-alias: README
|
||||
date created: Wednesday, April 17th 2024, 4:11:40 pm
|
||||
date modified: Thursday, April 18th 2024, 8:19:25 am
|
||||
---
|
||||
|
||||
## Shamir Secret Sharing Scheme
|
||||
|
||||
The code is an implementation of the following papers.
|
||||
|
||||
- <https://dl.acm.org/doi/pdf/10.1145/359168.359176>
|
||||
- <https://www.cs.umd.edu/>~gasarch/TOPICS/secretsharing/feldmanVSS.pdf
|
||||
- <https://link.springer.com/content/pdf/10.1007%2F3-540-46766-1_9.pdf>
|
||||
@@ -1,132 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package sharing
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
var testCurve = curves.ED25519()
|
||||
|
||||
func TestEd25519FeldmanSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewFeldman(0, 0, testCurve)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(3, 2, testCurve)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(1, 10, testCurve)
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewFeldman(2, 3, testCurve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, _, err = scheme.Split(testCurve.NewScalar(), crand.Reader)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, testCurve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, testCurve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Id: 1,
|
||||
Value: testCurve.Scalar.New(3).Bytes(),
|
||||
},
|
||||
{
|
||||
Id: 1,
|
||||
Value: testCurve.Scalar.New(3).Bytes(),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, testCurve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Id: 0,
|
||||
Value: testCurve.Scalar.New(3).Bytes(),
|
||||
},
|
||||
{
|
||||
Id: 2,
|
||||
Value: testCurve.Scalar.New(3).Bytes(),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Id: 4,
|
||||
Value: testCurve.Scalar.New(3).Bytes(),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanCombineSingle(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, testCurve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := testCurve.Scalar.Hash([]byte("test"))
|
||||
verifiers, shares, err := scheme.Split(secret, crand.Reader)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
for _, s := range shares {
|
||||
err = verifiers.Verify(s)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
secret2, err := scheme.Combine(shares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret2, secret)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanAllCombinations(t *testing.T) {
|
||||
scheme, err := NewFeldman(3, 5, testCurve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := testCurve.Scalar.Hash([]byte("test"))
|
||||
verifiers, shares, err := scheme.Split(secret, crand.Reader)
|
||||
for _, s := range shares {
|
||||
err = verifiers.Verify(s)
|
||||
require.Nil(t, err)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(shares[i], shares[j], shares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package sharing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
type FeldmanVerifier struct {
|
||||
Commitments []curves.Point
|
||||
}
|
||||
|
||||
func (v FeldmanVerifier) Verify(share *ShamirShare) error {
|
||||
curve := curves.GetCurveByName(v.Commitments[0].CurveName())
|
||||
err := share.Validate(curve)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
x := curve.Scalar.New(int(share.Id))
|
||||
i := curve.Scalar.One()
|
||||
rhs := v.Commitments[0]
|
||||
|
||||
for j := 1; j < len(v.Commitments); j++ {
|
||||
i = i.Mul(x)
|
||||
rhs = rhs.Add(v.Commitments[j].Mul(i))
|
||||
}
|
||||
sc, _ := curve.Scalar.SetBytes(share.Value)
|
||||
lhs := v.Commitments[0].Generator().Mul(sc)
|
||||
|
||||
if lhs.Equal(rhs) {
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
type Feldman struct {
|
||||
Threshold, Limit uint32
|
||||
Curve *curves.Curve
|
||||
}
|
||||
|
||||
func NewFeldman(threshold, limit uint32, curve *curves.Curve) (*Feldman, error) {
|
||||
if limit < threshold {
|
||||
return nil, fmt.Errorf("limit cannot be less than threshold")
|
||||
}
|
||||
if threshold < 2 {
|
||||
return nil, fmt.Errorf("threshold cannot be less than 2")
|
||||
}
|
||||
if limit > 255 {
|
||||
return nil, fmt.Errorf("cannot exceed 255 shares")
|
||||
}
|
||||
if curve == nil {
|
||||
return nil, fmt.Errorf("invalid curve")
|
||||
}
|
||||
return &Feldman{threshold, limit, curve}, nil
|
||||
}
|
||||
|
||||
func (f Feldman) Split(secret curves.Scalar, reader io.Reader) (*FeldmanVerifier, []*ShamirShare, error) {
|
||||
if secret.IsZero() {
|
||||
return nil, nil, fmt.Errorf("invalid secret")
|
||||
}
|
||||
shamir := &Shamir{
|
||||
threshold: f.Threshold,
|
||||
limit: f.Limit,
|
||||
curve: f.Curve,
|
||||
}
|
||||
shares, poly := shamir.getPolyAndShares(secret, reader)
|
||||
verifier := new(FeldmanVerifier)
|
||||
verifier.Commitments = make([]curves.Point, f.Threshold)
|
||||
for i := range verifier.Commitments {
|
||||
verifier.Commitments[i] = f.Curve.ScalarBaseMult(poly.Coefficients[i])
|
||||
}
|
||||
return verifier, shares, nil
|
||||
}
|
||||
|
||||
func (f Feldman) LagrangeCoeffs(shares map[uint32]*ShamirShare) (map[uint32]curves.Scalar, error) {
|
||||
shamir := &Shamir{
|
||||
threshold: f.Threshold,
|
||||
limit: f.Limit,
|
||||
curve: f.Curve,
|
||||
}
|
||||
identities := make([]uint32, 0)
|
||||
for _, xi := range shares {
|
||||
identities = append(identities, xi.Id)
|
||||
}
|
||||
return shamir.LagrangeCoeffs(identities)
|
||||
}
|
||||
|
||||
func (f Feldman) Combine(shares ...*ShamirShare) (curves.Scalar, error) {
|
||||
shamir := &Shamir{
|
||||
threshold: f.Threshold,
|
||||
limit: f.Limit,
|
||||
curve: f.Curve,
|
||||
}
|
||||
return shamir.Combine(shares...)
|
||||
}
|
||||
|
||||
func (f Feldman) CombinePoints(shares ...*ShamirShare) (curves.Point, error) {
|
||||
shamir := &Shamir{
|
||||
threshold: f.Threshold,
|
||||
limit: f.Limit,
|
||||
curve: f.Curve,
|
||||
}
|
||||
return shamir.CombinePoints(shares...)
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package sharing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
// Pedersen Verifiable Secret Sharing Scheme
|
||||
type Pedersen struct {
|
||||
threshold, limit uint32
|
||||
curve *curves.Curve
|
||||
generator curves.Point
|
||||
}
|
||||
|
||||
type PedersenVerifier struct {
|
||||
Generator curves.Point
|
||||
Commitments []curves.Point
|
||||
}
|
||||
|
||||
func (pv PedersenVerifier) Verify(share, blindShare *ShamirShare) error {
|
||||
curve := curves.GetCurveByName(pv.Generator.CurveName())
|
||||
if err := share.Validate(curve); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := blindShare.Validate(curve); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
x := curve.Scalar.New(int(share.Id))
|
||||
i := curve.Scalar.One()
|
||||
rhs := pv.Commitments[0]
|
||||
|
||||
for j := 1; j < len(pv.Commitments); j++ {
|
||||
i = i.Mul(x)
|
||||
rhs = rhs.Add(pv.Commitments[j].Mul(i))
|
||||
}
|
||||
|
||||
sc, _ := curve.Scalar.SetBytes(share.Value)
|
||||
bsc, _ := curve.Scalar.SetBytes(blindShare.Value)
|
||||
g := pv.Commitments[0].Generator().Mul(sc)
|
||||
h := pv.Generator.Mul(bsc)
|
||||
lhs := g.Add(h)
|
||||
|
||||
if lhs.Equal(rhs) {
|
||||
return nil
|
||||
} else {
|
||||
return fmt.Errorf("not equal")
|
||||
}
|
||||
}
|
||||
|
||||
// PedersenResult contains all the data from calling Split
|
||||
type PedersenResult struct {
|
||||
Blinding curves.Scalar
|
||||
BlindingShares, SecretShares []*ShamirShare
|
||||
FeldmanVerifier *FeldmanVerifier
|
||||
PedersenVerifier *PedersenVerifier
|
||||
}
|
||||
|
||||
// NewPedersen creates a new pedersen VSS
|
||||
func NewPedersen(threshold, limit uint32, generator curves.Point) (*Pedersen, error) {
|
||||
if limit < threshold {
|
||||
return nil, fmt.Errorf("limit cannot be less than threshold")
|
||||
}
|
||||
if threshold < 2 {
|
||||
return nil, fmt.Errorf("threshold cannot be less than 2")
|
||||
}
|
||||
if limit > 255 {
|
||||
return nil, fmt.Errorf("cannot exceed 255 shares")
|
||||
}
|
||||
curve := curves.GetCurveByName(generator.CurveName())
|
||||
if curve == nil {
|
||||
return nil, fmt.Errorf("invalid curve")
|
||||
}
|
||||
if generator == nil {
|
||||
return nil, fmt.Errorf("invalid generator")
|
||||
}
|
||||
if !generator.IsOnCurve() || generator.IsIdentity() {
|
||||
return nil, fmt.Errorf("invalid generator")
|
||||
}
|
||||
return &Pedersen{threshold, limit, curve, generator}, nil
|
||||
}
|
||||
|
||||
// Split creates the verifiers, blinding and shares
|
||||
func (pd Pedersen) Split(secret curves.Scalar, reader io.Reader) (*PedersenResult, error) {
|
||||
// generate a random blinding factor
|
||||
blinding := pd.curve.Scalar.Random(reader)
|
||||
|
||||
shamir := Shamir{pd.threshold, pd.limit, pd.curve}
|
||||
// split the secret into shares
|
||||
shares, poly := shamir.getPolyAndShares(secret, reader)
|
||||
|
||||
// split the blinding into shares
|
||||
blindingShares, polyBlinding := shamir.getPolyAndShares(blinding, reader)
|
||||
|
||||
// Generate the verifiable commitments to the polynomial for the shares
|
||||
blindedverifiers := make([]curves.Point, pd.threshold)
|
||||
verifiers := make([]curves.Point, pd.threshold)
|
||||
|
||||
// ({p0 * G + b0 * H}, ...,{pt * G + bt * H})
|
||||
for i, c := range poly.Coefficients {
|
||||
s := pd.curve.ScalarBaseMult(c)
|
||||
b := pd.generator.Mul(polyBlinding.Coefficients[i])
|
||||
bv := s.Add(b)
|
||||
blindedverifiers[i] = bv
|
||||
verifiers[i] = s
|
||||
}
|
||||
verifier1 := &FeldmanVerifier{Commitments: verifiers}
|
||||
verifier2 := &PedersenVerifier{Commitments: blindedverifiers, Generator: pd.generator}
|
||||
|
||||
return &PedersenResult{
|
||||
blinding, blindingShares, shares, verifier1, verifier2,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (pd Pedersen) LagrangeCoeffs(shares map[uint32]*ShamirShare) (map[uint32]curves.Scalar, error) {
|
||||
shamir := &Shamir{
|
||||
threshold: pd.threshold,
|
||||
limit: pd.limit,
|
||||
curve: pd.curve,
|
||||
}
|
||||
identities := make([]uint32, 0)
|
||||
for _, xi := range shares {
|
||||
identities = append(identities, xi.Id)
|
||||
}
|
||||
return shamir.LagrangeCoeffs(identities)
|
||||
}
|
||||
|
||||
func (pd Pedersen) Combine(shares ...*ShamirShare) (curves.Scalar, error) {
|
||||
shamir := &Shamir{
|
||||
threshold: pd.threshold,
|
||||
limit: pd.limit,
|
||||
curve: pd.curve,
|
||||
}
|
||||
return shamir.Combine(shares...)
|
||||
}
|
||||
|
||||
func (pd Pedersen) CombinePoints(shares ...*ShamirShare) (curves.Point, error) {
|
||||
shamir := &Shamir{
|
||||
threshold: pd.threshold,
|
||||
limit: pd.limit,
|
||||
curve: pd.curve,
|
||||
}
|
||||
return shamir.CombinePoints(shares...)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package sharing
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
type Polynomial struct {
|
||||
Coefficients []curves.Scalar
|
||||
}
|
||||
|
||||
func (p *Polynomial) Init(intercept curves.Scalar, degree uint32, reader io.Reader) *Polynomial {
|
||||
p.Coefficients = make([]curves.Scalar, degree)
|
||||
p.Coefficients[0] = intercept.Clone()
|
||||
for i := 1; i < int(degree); i++ {
|
||||
p.Coefficients[i] = intercept.Random(reader)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (p Polynomial) Evaluate(x curves.Scalar) curves.Scalar {
|
||||
degree := len(p.Coefficients) - 1
|
||||
out := p.Coefficients[degree].Clone()
|
||||
for i := degree - 1; i >= 0; i-- {
|
||||
out = out.Mul(x).Add(p.Coefficients[i])
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package sharing
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestNewPoly(t *testing.T) {
|
||||
curve := curves.BLS12381G1()
|
||||
secret := curve.NewScalar().Hash([]byte("test"))
|
||||
|
||||
poly := new(Polynomial).Init(secret, 4, crand.Reader)
|
||||
require.NotNil(t, poly)
|
||||
|
||||
require.Equal(t, poly.Coefficients[0], secret)
|
||||
}
|
||||
@@ -1,206 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Package sharing is an implementation of shamir secret sharing and implements the following papers.
|
||||
//
|
||||
// - https://dl.acm.org/doi/pdf/10.1145/359168.359176
|
||||
// - https://www.cs.umd.edu/~gasarch/TOPICS/secretsharing/feldmanVSS.pdf
|
||||
// - https://link.springer.com/content/pdf/10.1007%2F3-540-46766-1_9.pdf
|
||||
package sharing
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
type ShamirShare struct {
|
||||
Id uint32 `json:"identifier"`
|
||||
Value []byte `json:"value"`
|
||||
}
|
||||
|
||||
func (ss ShamirShare) Validate(curve *curves.Curve) error {
|
||||
if ss.Id == 0 {
|
||||
return fmt.Errorf("invalid identifier")
|
||||
}
|
||||
sc, err := curve.Scalar.SetBytes(ss.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if sc.IsZero() {
|
||||
return fmt.Errorf("invalid share")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ss ShamirShare) Bytes() []byte {
|
||||
var id [4]byte
|
||||
binary.BigEndian.PutUint32(id[:], ss.Id)
|
||||
return append(id[:], ss.Value...)
|
||||
}
|
||||
|
||||
type Shamir struct {
|
||||
threshold, limit uint32
|
||||
curve *curves.Curve
|
||||
}
|
||||
|
||||
func NewShamir(threshold, limit uint32, curve *curves.Curve) (*Shamir, error) {
|
||||
if limit < threshold {
|
||||
return nil, fmt.Errorf("limit cannot be less than threshold")
|
||||
}
|
||||
if threshold < 2 {
|
||||
return nil, fmt.Errorf("threshold cannot be less than 2")
|
||||
}
|
||||
if limit > 255 {
|
||||
return nil, fmt.Errorf("cannot exceed 255 shares")
|
||||
}
|
||||
if curve == nil {
|
||||
return nil, fmt.Errorf("invalid curve")
|
||||
}
|
||||
return &Shamir{threshold, limit, curve}, nil
|
||||
}
|
||||
|
||||
func (s Shamir) Split(secret curves.Scalar, reader io.Reader) ([]*ShamirShare, error) {
|
||||
if secret.IsZero() {
|
||||
return nil, fmt.Errorf("invalid secret")
|
||||
}
|
||||
shares, _ := s.getPolyAndShares(secret, reader)
|
||||
return shares, nil
|
||||
}
|
||||
|
||||
func (s Shamir) getPolyAndShares(secret curves.Scalar, reader io.Reader) ([]*ShamirShare, *Polynomial) {
|
||||
poly := new(Polynomial).Init(secret, s.threshold, reader)
|
||||
shares := make([]*ShamirShare, s.limit)
|
||||
for i := range shares {
|
||||
x := s.curve.Scalar.New(i + 1)
|
||||
shares[i] = &ShamirShare{
|
||||
Id: uint32(i + 1),
|
||||
Value: poly.Evaluate(x).Bytes(),
|
||||
}
|
||||
}
|
||||
return shares, poly
|
||||
}
|
||||
|
||||
func (s Shamir) LagrangeCoeffs(identities []uint32) (map[uint32]curves.Scalar, error) {
|
||||
xs := make(map[uint32]curves.Scalar, len(identities))
|
||||
for _, xi := range identities {
|
||||
xs[xi] = s.curve.Scalar.New(int(xi))
|
||||
}
|
||||
|
||||
result := make(map[uint32]curves.Scalar, len(identities))
|
||||
for i, xi := range xs {
|
||||
num := s.curve.Scalar.One()
|
||||
den := s.curve.Scalar.One()
|
||||
for j, xj := range xs {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
|
||||
num = num.Mul(xj)
|
||||
den = den.Mul(xj.Sub(xi))
|
||||
}
|
||||
if den.IsZero() {
|
||||
return nil, fmt.Errorf("divide by zero")
|
||||
}
|
||||
result[i] = num.Div(den)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s Shamir) Combine(shares ...*ShamirShare) (curves.Scalar, error) {
|
||||
if len(shares) < int(s.threshold) {
|
||||
return nil, fmt.Errorf("invalid number of shares")
|
||||
}
|
||||
dups := make(map[uint32]bool, len(shares))
|
||||
xs := make([]curves.Scalar, len(shares))
|
||||
ys := make([]curves.Scalar, len(shares))
|
||||
|
||||
for i, share := range shares {
|
||||
err := share.Validate(s.curve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if share.Id > s.limit {
|
||||
return nil, fmt.Errorf("invalid share identifier")
|
||||
}
|
||||
if _, in := dups[share.Id]; in {
|
||||
return nil, fmt.Errorf("duplicate share")
|
||||
}
|
||||
dups[share.Id] = true
|
||||
ys[i], _ = s.curve.Scalar.SetBytes(share.Value)
|
||||
xs[i] = s.curve.Scalar.New(int(share.Id))
|
||||
}
|
||||
return s.interpolate(xs, ys)
|
||||
}
|
||||
|
||||
func (s Shamir) CombinePoints(shares ...*ShamirShare) (curves.Point, error) {
|
||||
if len(shares) < int(s.threshold) {
|
||||
return nil, fmt.Errorf("invalid number of shares")
|
||||
}
|
||||
dups := make(map[uint32]bool, len(shares))
|
||||
xs := make([]curves.Scalar, len(shares))
|
||||
ys := make([]curves.Point, len(shares))
|
||||
|
||||
for i, share := range shares {
|
||||
err := share.Validate(s.curve)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if share.Id > s.limit {
|
||||
return nil, fmt.Errorf("invalid share identifier")
|
||||
}
|
||||
if _, in := dups[share.Id]; in {
|
||||
return nil, fmt.Errorf("duplicate share")
|
||||
}
|
||||
dups[share.Id] = true
|
||||
sc, _ := s.curve.Scalar.SetBytes(share.Value)
|
||||
ys[i] = s.curve.ScalarBaseMult(sc)
|
||||
xs[i] = s.curve.Scalar.New(int(share.Id))
|
||||
}
|
||||
return s.interpolatePoint(xs, ys)
|
||||
}
|
||||
|
||||
func (s Shamir) interpolate(xs, ys []curves.Scalar) (curves.Scalar, error) {
|
||||
result := s.curve.Scalar.Zero()
|
||||
for i, xi := range xs {
|
||||
num := s.curve.Scalar.One()
|
||||
den := s.curve.Scalar.One()
|
||||
for j, xj := range xs {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
num = num.Mul(xj)
|
||||
den = den.Mul(xj.Sub(xi))
|
||||
}
|
||||
if den.IsZero() {
|
||||
return nil, fmt.Errorf("divide by zero")
|
||||
}
|
||||
result = result.Add(ys[i].Mul(num.Div(den)))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s Shamir) interpolatePoint(xs []curves.Scalar, ys []curves.Point) (curves.Point, error) {
|
||||
result := s.curve.NewIdentityPoint()
|
||||
for i, xi := range xs {
|
||||
num := s.curve.Scalar.One()
|
||||
den := s.curve.Scalar.One()
|
||||
for j, xj := range xs {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
num = num.Mul(xj)
|
||||
den = den.Mul(xj.Sub(xi))
|
||||
}
|
||||
if den.IsZero() {
|
||||
return nil, fmt.Errorf("divide by zero")
|
||||
}
|
||||
result = result.Add(ys[i].Mul(num.Div(den)))
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package sharing
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
crand "crypto/rand"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestShamirSplitInvalidArgs(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
_, err := NewShamir(0, 0, curve)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewShamir(3, 2, curve)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewShamir(1, 10, curve)
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewShamir(2, 3, curve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Split(curve.NewScalar(), crand.Reader)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestShamirCombineNoShares(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
scheme, err := NewShamir(2, 3, curve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestShamirCombineDuplicateShare(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
scheme, err := NewShamir(2, 3, curve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Id: 1,
|
||||
Value: curve.NewScalar().New(3).Bytes(),
|
||||
},
|
||||
{
|
||||
Id: 1,
|
||||
Value: curve.NewScalar().New(3).Bytes(),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestShamirCombineBadIdentifier(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
scheme, err := NewShamir(2, 3, curve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Id: 0,
|
||||
Value: curve.NewScalar().New(3).Bytes(),
|
||||
},
|
||||
{
|
||||
Id: 2,
|
||||
Value: curve.NewScalar().New(3).Bytes(),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Id: 4,
|
||||
Value: curve.NewScalar().New(3).Bytes(),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestShamirCombineSingle(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
scheme, err := NewShamir(2, 3, curve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
shares, err := scheme.Split(curve.NewScalar().Hash([]byte("test")), crand.Reader)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
secret, err := scheme.Combine(shares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret, curve.NewScalar().Hash([]byte("test")))
|
||||
}
|
||||
|
||||
// Test ComputeL function to compute Lagrange coefficients.
|
||||
func TestShamirComputeL(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
scheme, err := NewShamir(2, 2, curve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
secret := curve.Scalar.Hash([]byte("test"))
|
||||
shares, err := scheme.Split(secret, crand.Reader)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
identities := make([]uint32, 0)
|
||||
for _, xi := range shares {
|
||||
identities = append(identities, xi.Id)
|
||||
}
|
||||
lCoeffs, err := scheme.LagrangeCoeffs(identities)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, lCoeffs)
|
||||
|
||||
// Checking we can reconstruct the same secret using Lagrange coefficients.
|
||||
result := curve.NewScalar()
|
||||
for _, r := range shares {
|
||||
rc, _ := curve.Scalar.SetBytes(r.Value)
|
||||
result = result.Add(rc.Mul(lCoeffs[r.Id]))
|
||||
}
|
||||
require.Equal(t, result.Bytes(), secret.Bytes())
|
||||
}
|
||||
|
||||
func TestShamirAllCombinations(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
scheme, err := NewShamir(3, 5, curve)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := curve.Scalar.Hash([]byte("test"))
|
||||
shares, err := scheme.Split(secret, crand.Reader)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(shares[i], shares[j], shares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures that ShamirShare's un/marshal successfully.
|
||||
func TestMarshalJsonRoundTrip(t *testing.T) {
|
||||
curve := curves.ED25519()
|
||||
shares := []ShamirShare{
|
||||
{0, curve.Scalar.New(300).Bytes()},
|
||||
{2, curve.Scalar.New(300000).Bytes()},
|
||||
{20, curve.Scalar.New(12812798).Bytes()},
|
||||
{31, curve.Scalar.New(17).Bytes()},
|
||||
{57, curve.Scalar.New(5066680).Bytes()},
|
||||
{128, curve.Scalar.New(3005).Bytes()},
|
||||
{19, curve.Scalar.New(317).Bytes()},
|
||||
{7, curve.Scalar.New(323).Bytes()},
|
||||
{222, curve.NewScalar().New(-1).Bytes()},
|
||||
}
|
||||
// Run all the tests!
|
||||
for _, in := range shares {
|
||||
input, err := json.Marshal(in)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, input)
|
||||
|
||||
// Unmarshal and test
|
||||
out := &ShamirShare{}
|
||||
// out.Value = curve.NewScalar()
|
||||
err = json.Unmarshal(input, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, in.Id, out.Id)
|
||||
require.Equal(t, bytes.Compare(in.Value, out.Value), 0)
|
||||
}
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
var (
|
||||
modulus, _ = new(big.Int).SetString(
|
||||
"1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED",
|
||||
16,
|
||||
)
|
||||
field = curves.NewField(modulus)
|
||||
)
|
||||
|
||||
func TestBls12381G1FeldmanSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewFeldman(0, 0, Bls12381G1())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(3, 2, Bls12381G1())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(1, 10, Bls12381G1())
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G1())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, _, err = scheme.Split([]byte{})
|
||||
require.NotNil(t, err)
|
||||
_, _, err = scheme.Split([]byte{0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65})
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestBls12381G1FeldmanCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G1())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestBls12381G1FeldmanCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G1())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestBls12381G1FeldmanCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G1())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Identifier: 0,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 2,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Identifier: 4,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestBls12381G1FeldmanCombineSingle(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G1())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
verifiers, shares, err := scheme.Split([]byte("test"))
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
secret, err := scheme.Combine(shares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret, []byte("test"))
|
||||
}
|
||||
|
||||
func TestBls12381G1FeldmanAllCombinations(t *testing.T) {
|
||||
scheme, err := NewFeldman(3, 5, Bls12381G1())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := []byte("test")
|
||||
verifiers, shares, err := scheme.Split(secret)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(shares[i], shares[j], shares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves/native"
|
||||
"github.com/onsonr/sonr/crypto/core/curves/native/bls12381"
|
||||
"github.com/onsonr/sonr/crypto/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
bls12381g1Initonce sync.Once
|
||||
bls12381g1 Bls12381G1Curve
|
||||
)
|
||||
|
||||
type Bls12381G1Curve struct {
|
||||
*elliptic.CurveParams
|
||||
}
|
||||
|
||||
func bls12381g1InitAll() {
|
||||
bls12381g1.CurveParams = new(elliptic.CurveParams)
|
||||
bls12381g1.P, _ = new(big.Int).SetString("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16)
|
||||
bls12381g1.N = bls12381.Bls12381FqNew().Params.BiModulus
|
||||
bls12381g1.B, _ = new(big.Int).SetString("0bbc3efc5008a26a0e1c8c3fad0059c051ac582950405194dd595f13570725ce8c22631a7918fd8ebaac93d50ce72271", 16)
|
||||
bls12381g1.Gx, _ = new(big.Int).SetString("120177419e0bfb75edce6ecc21dbf440f0ae6acdf3d0e747154f95c7143ba1c17817fc679976fff55cb38790fd530c16", 16)
|
||||
bls12381g1.Gy, _ = new(big.Int).SetString("0bbc3efc5008a26a0e1c8c3fad0059c051ac582950405194dd595f13570725ce8c22631a7918fd8ebaac93d50ce72271", 16)
|
||||
bls12381g1.BitSize = 381
|
||||
bls12381g1.Name = "Bls12381G1"
|
||||
}
|
||||
|
||||
func Bls12381G1() *Bls12381G1Curve {
|
||||
bls12381g1Initonce.Do(bls12381g1InitAll)
|
||||
return &bls12381g1
|
||||
}
|
||||
|
||||
func (curve *Bls12381G1Curve) Params() *elliptic.CurveParams {
|
||||
return curve.CurveParams
|
||||
}
|
||||
|
||||
func (curve *Bls12381G1Curve) IsOnCurve(x, y *big.Int) bool {
|
||||
_, err := new(bls12381.G1).SetBigInt(x, y)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (curve *Bls12381G1Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
|
||||
p1, err1 := new(bls12381.G1).SetBigInt(x1, y1)
|
||||
p2, err2 := new(bls12381.G1).SetBigInt(x2, y2)
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p1.Add(p1, p2).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Bls12381G1Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
|
||||
p, err := new(bls12381.G1).SetBigInt(x1, y1)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p.Double(p).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Bls12381G1Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
|
||||
p, err := new(bls12381.G1).SetBigInt(Bx, By)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
var bb [native.FieldBytes]byte
|
||||
copy(bb[:], k)
|
||||
s, err := bls12381.Bls12381FqNew().SetBytes(&bb)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p.Mul(p, s).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Bls12381G1Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
|
||||
p := new(bls12381.G1).Generator()
|
||||
var bb [native.FieldBytes]byte
|
||||
copy(bb[:], internal.ReverseScalarBytes(k))
|
||||
s, err := bls12381.Bls12381FqNew().SetBytes(&bb)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p.Mul(p, s).BigInt()
|
||||
}
|
||||
|
||||
// Hash an arbitrary byte sequence to a G1 point according to the hash-to-curve standard
|
||||
func (curve *Bls12381G1Curve) Hash(msg []byte) (*big.Int, *big.Int) {
|
||||
return new(bls12381.G1).Hash(native.EllipticPointHasherSha256(), msg, []byte("BLS12381G1_XMD:SHA-256_SSWU_RO_")).BigInt()
|
||||
}
|
||||
|
||||
// CompressedBytesFromBigInts takes x and y coordinates and converts them to the BLS compressed point form
|
||||
func (curve *Bls12381G1Curve) CompressedBytesFromBigInts(x, y *big.Int) ([]byte, error) {
|
||||
p, err := new(bls12381.G1).SetBigInt(x, y)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := p.ToCompressed()
|
||||
return out[:], nil
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestBls12381G2FeldmanSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewFeldman(0, 0, Bls12381G2())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(3, 2, Bls12381G2())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(1, 10, Bls12381G2())
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G2())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, _, err = scheme.Split([]byte{})
|
||||
require.NotNil(t, err)
|
||||
_, _, err = scheme.Split([]byte{0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65})
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestBls12381G2FeldmanCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G2())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestBls12381G2FeldmanCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G2())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestBls12381G2FeldmanCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G2())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Identifier: 0,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 2,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Identifier: 4,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestBls12381G2FeldmanCombineSingle(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Bls12381G2())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
verifiers, shares, err := scheme.Split([]byte("test"))
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
secret, err := scheme.Combine(shares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret, []byte("test"))
|
||||
}
|
||||
|
||||
func TestBls12381G2FeldmanAllCombinations(t *testing.T) {
|
||||
scheme, err := NewFeldman(3, 5, Bls12381G2())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := []byte("test")
|
||||
verifiers, shares, err := scheme.Split(secret)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(shares[i], shares[j], shares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves/native"
|
||||
"github.com/onsonr/sonr/crypto/core/curves/native/bls12381"
|
||||
)
|
||||
|
||||
var (
|
||||
bls12381g2Initonce sync.Once
|
||||
bls12381g2 Bls12381G2Curve
|
||||
)
|
||||
|
||||
type Bls12381G2Curve struct {
|
||||
*elliptic.CurveParams
|
||||
}
|
||||
|
||||
func bls12381g2InitAll() {
|
||||
bls12381g2.CurveParams = new(elliptic.CurveParams)
|
||||
bls12381g2.P, _ = new(big.Int).SetString("1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaab", 16)
|
||||
bls12381g2.N = bls12381.Bls12381FqNew().Params.BiModulus
|
||||
bls12381g2.B, _ = new(big.Int).SetString("0bbc3efc5008a26a0e1c8c3fad0059c051ac582950405194dd595f13570725ce8c22631a7918fd8ebaac93d50ce72271", 16)
|
||||
bls12381g2.Gx, _ = new(big.Int).SetString("120177419e0bfb75edce6ecc21dbf440f0ae6acdf3d0e747154f95c7143ba1c17817fc679976fff55cb38790fd530c16", 16)
|
||||
bls12381g2.Gy, _ = new(big.Int).SetString("0bbc3efc5008a26a0e1c8c3fad0059c051ac582950405194dd595f13570725ce8c22631a7918fd8ebaac93d50ce72271", 16)
|
||||
bls12381g2.BitSize = 381
|
||||
bls12381g2.Name = "Bls12381G1"
|
||||
}
|
||||
|
||||
func Bls12381G2() *Bls12381G1Curve {
|
||||
bls12381g2Initonce.Do(bls12381g2InitAll)
|
||||
return &bls12381g1
|
||||
}
|
||||
|
||||
func (curve *Bls12381G2Curve) Params() *elliptic.CurveParams {
|
||||
return curve.CurveParams
|
||||
}
|
||||
|
||||
func (curve *Bls12381G2Curve) IsOnCurve(x, y *big.Int) bool {
|
||||
_, err := new(bls12381.G2).SetBigInt(x, y)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (curve *Bls12381G2Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
|
||||
p1, err1 := new(bls12381.G2).SetBigInt(x1, y1)
|
||||
p2, err2 := new(bls12381.G2).SetBigInt(x2, y2)
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p1.Add(p1, p2).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Bls12381G2Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
|
||||
p, err := new(bls12381.G2).SetBigInt(x1, y1)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p.Double(p).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Bls12381G2Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
|
||||
p, err := new(bls12381.G2).SetBigInt(Bx, By)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
var bb [native.FieldBytes]byte
|
||||
copy(bb[:], k)
|
||||
s, err := bls12381.Bls12381FqNew().SetBytes(&bb)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p.Mul(p, s).BigInt()
|
||||
}
|
||||
|
||||
func (curve *Bls12381G2Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
|
||||
p := new(bls12381.G2).Generator()
|
||||
var bb [native.FieldBytes]byte
|
||||
copy(bb[:], k)
|
||||
s, err := bls12381.Bls12381FqNew().SetBytes(&bb)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
return p.Mul(p, s).BigInt()
|
||||
}
|
||||
|
||||
// Hash an arbitrary byte sequence to a G1 point according to the hash-to-curve standard
|
||||
func (curve *Bls12381G2Curve) Hash(msg []byte) (*big.Int, *big.Int) {
|
||||
return new(bls12381.G1).Hash(native.EllipticPointHasherSha256(), msg, []byte("BLS12381G2_XMD:SHA-256_SSWU_RO_")).BigInt()
|
||||
}
|
||||
|
||||
// CompressedBytesFromBigInts takes x and y coordinates and converts them to the BLS compressed point form
|
||||
func (curve *Bls12381G2Curve) CompressedBytesFromBigInts(x, y *big.Int) ([]byte, error) {
|
||||
p, err := new(bls12381.G2).SetBigInt(x, y)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := p.ToCompressed()
|
||||
return out[:], nil
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
kryptology "github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
// ShareVerifier is used to verify secret shares from Feldman or Pedersen VSS
|
||||
type ShareVerifier = kryptology.EcPoint
|
||||
@@ -1,131 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEd25519FeldmanSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewFeldman(0, 0, Ed25519())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(3, 2, Ed25519())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(1, 10, Ed25519())
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewFeldman(2, 3, Ed25519())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, _, err = scheme.Split([]byte{})
|
||||
require.NotNil(t, err)
|
||||
_, _, err = scheme.Split([]byte{0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65})
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Ed25519())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Ed25519())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Ed25519())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Identifier: 0,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 2,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Identifier: 4,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanCombineSingle(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, Ed25519())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
verifiers, shares, err := scheme.Split([]byte("test"))
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
secret, err := scheme.Combine(shares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret, []byte("test"))
|
||||
}
|
||||
|
||||
func TestEd25519FeldmanAllCombinations(t *testing.T) {
|
||||
scheme, err := NewFeldman(3, 5, Ed25519())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := []byte("test")
|
||||
verifiers, shares, err := scheme.Split(secret)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(shares[i], shares[j], shares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"filippo.io/edwards25519"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
core "github.com/onsonr/sonr/crypto/core/curves"
|
||||
"github.com/onsonr/sonr/crypto/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
ed25519BasePoint = &core.EcPoint{Curve: Ed25519(), X: Ed25519().Gx, Y: Ed25519().Gy}
|
||||
testPointEd25519, _ = core.NewScalarBaseMult(Ed25519(), big.NewInt(2222))
|
||||
)
|
||||
|
||||
func TestEd25519PedersenSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewPedersen(0, 0, nil)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewPedersen(3, 2, nil)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewPedersen(1, 10, nil)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewPedersen(2, 3, nil)
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewPedersen(2, 3, ed25519BasePoint)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Split([]byte{})
|
||||
require.NotNil(t, err)
|
||||
// test that split doesn't work on secrets bigger than the modulus
|
||||
_, err = scheme.Split([]byte{0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65})
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519PedersenCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewPedersen(2, 3, ed25519BasePoint)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519PedersenCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewPedersen(2, 3, ed25519BasePoint)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519PedersenCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewPedersen(2, 3, ed25519BasePoint)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Identifier: 0,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 2,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Identifier: 4,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestEd25519PedersenCombineSingle(t *testing.T) {
|
||||
scheme, err := NewPedersen(2, 3, testPointEd25519)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
hBytes := sha512.Sum512([]byte("test"))
|
||||
var arr [32]byte
|
||||
copy(arr[:], hBytes[:])
|
||||
sc, err := edwards25519.NewScalar().SetBytesWithClamping(arr[:])
|
||||
require.Nil(t, err)
|
||||
result, err := scheme.Split(internal.ReverseScalarBytes(sc.Bytes()))
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, result)
|
||||
for i, s := range result.SecretShares {
|
||||
ok, err := scheme.Verify(s, result.BlindingShares[i], result.BlindedVerifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
secret, err := scheme.Combine(result.SecretShares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, internal.ReverseScalarBytes(secret), sc.Bytes())
|
||||
}
|
||||
|
||||
func TestEd25519PedersenAllCombinations(t *testing.T) {
|
||||
scheme, err := NewPedersen(3, 5, testPointEd25519)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := []byte("test")
|
||||
result, err := scheme.Split(secret)
|
||||
for i, s := range result.SecretShares {
|
||||
ok, err := scheme.Verify(s, result.BlindingShares[i], result.BlindedVerifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, result)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(result.SecretShares[i], result.SecretShares[j], result.SecretShares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
|
||||
bSecret, err := scheme.Combine(result.BlindingShares[i], result.BlindingShares[j], result.BlindingShares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, bSecret)
|
||||
require.Equal(t, bSecret, result.Blinding.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
ed "filippo.io/edwards25519"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
"github.com/onsonr/sonr/crypto/internal"
|
||||
)
|
||||
|
||||
var (
|
||||
ed25519Initonce sync.Once
|
||||
ed25519 Ed25519Curve
|
||||
)
|
||||
|
||||
type Ed25519Curve struct {
|
||||
*elliptic.CurveParams
|
||||
}
|
||||
|
||||
func ed25519InitAll() {
|
||||
// taken from https://datatracker.ietf.org/doc/html/rfc8032
|
||||
ed25519.CurveParams = new(elliptic.CurveParams)
|
||||
ed25519.P, _ = new(big.Int).SetString("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFED", 16)
|
||||
ed25519.N, _ = new(big.Int).SetString("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED", 16)
|
||||
ed25519.Gx = new(big.Int)
|
||||
ed25519.Gy = new(big.Int).SetBytes(ed.NewGeneratorPoint().Bytes())
|
||||
ed25519.BitSize = 255
|
||||
ed25519.Name = "ed25519"
|
||||
}
|
||||
|
||||
func Ed25519() *Ed25519Curve {
|
||||
ed25519Initonce.Do(ed25519InitAll)
|
||||
return &ed25519
|
||||
}
|
||||
|
||||
func (curve *Ed25519Curve) Params() *elliptic.CurveParams {
|
||||
return curve.CurveParams
|
||||
}
|
||||
|
||||
func (curve *Ed25519Curve) IsOnCurve(x, y *big.Int) bool {
|
||||
// ignore the x value since Ed25519 is canonical 32 bytes of y according to RFC 8032
|
||||
// Set bytes returns an error if not a valid point
|
||||
_, err := internal.BigInt2Ed25519Point(y)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (curve *Ed25519Curve) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
|
||||
var p1, p2 *ed.Point
|
||||
var err error
|
||||
if y1.Cmp(big.NewInt(0)) == 0 {
|
||||
p1 = ed.NewIdentityPoint()
|
||||
} else {
|
||||
p1, err = internal.BigInt2Ed25519Point(y1)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if y2.Cmp(big.NewInt(0)) == 0 {
|
||||
p2 = ed.NewIdentityPoint()
|
||||
} else {
|
||||
p2, err = internal.BigInt2Ed25519Point(y2)
|
||||
}
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p1.Add(p1, p2)
|
||||
return new(big.Int), new(big.Int).SetBytes(p1.Bytes())
|
||||
}
|
||||
|
||||
func (curve *Ed25519Curve) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
|
||||
p, err := internal.BigInt2Ed25519Point(y1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
p1, _ := internal.BigInt2Ed25519Point(y1)
|
||||
p.Add(p, p1)
|
||||
return new(big.Int), new(big.Int).SetBytes(p.Bytes())
|
||||
}
|
||||
|
||||
func (curve *Ed25519Curve) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
|
||||
p, err := internal.BigInt2Ed25519Point(By)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
s, err := internal.BigInt2Ed25519Scalar(new(big.Int).SetBytes(k))
|
||||
if err != nil {
|
||||
var t [64]byte
|
||||
copy(t[:], internal.ReverseScalarBytes(k))
|
||||
s, err = ed.NewScalar().SetUniformBytes(t[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
p.ScalarMult(s, p)
|
||||
return new(big.Int), new(big.Int).SetBytes(p.Bytes())
|
||||
}
|
||||
|
||||
func (curve *Ed25519Curve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
|
||||
s, err := internal.BigInt2Ed25519Scalar(new(big.Int).SetBytes(k))
|
||||
if err != nil {
|
||||
var t [64]byte
|
||||
copy(t[:], internal.ReverseScalarBytes(k))
|
||||
s, err = ed.NewScalar().SetUniformBytes(t[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
p := ed.NewIdentityPoint().ScalarBaseMult(s)
|
||||
return new(big.Int), new(big.Int).SetBytes(p.Bytes())
|
||||
}
|
||||
|
||||
func (curve *Ed25519Curve) Neg(Bx, By *big.Int) (*big.Int, *big.Int) {
|
||||
var p1 *ed.Point
|
||||
var err error
|
||||
if By.Cmp(big.NewInt(0)) == 0 {
|
||||
p1 = ed.NewIdentityPoint()
|
||||
} else {
|
||||
p1, err = internal.BigInt2Ed25519Point(By)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
p1.Negate(p1)
|
||||
return new(big.Int), new(big.Int).SetBytes(p1.Bytes())
|
||||
}
|
||||
|
||||
func (curve *Ed25519Curve) Hash(msg []byte) (*big.Int, *big.Int) {
|
||||
data := new(curves.PointEd25519).Hash(msg).ToAffineCompressed()
|
||||
pt, err := ed.NewIdentityPoint().SetBytes(data)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return new(big.Int), new(big.Int).SetBytes(internal.ReverseScalarBytes(pt.Bytes()))
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEd25519ScalarMult(t *testing.T) {
|
||||
// These values were caught during testing where this combination
|
||||
// yields leading zeros in which big.Int chops.
|
||||
// This test makes sure that this case is correctly handled
|
||||
y := new(big.Int).SetBytes([]byte{37, 228, 49, 105, 78, 97, 108, 221, 63, 25, 125, 212, 108, 189, 247, 169, 52, 86, 150, 97, 93, 199, 212, 254, 122, 98, 189, 7, 97, 14, 78, 12})
|
||||
x := new(big.Int).SetInt64(4)
|
||||
curve := Ed25519()
|
||||
require.True(t, curve.IsOnCurve(nil, y))
|
||||
_, newY := curve.ScalarMult(nil, y, x.Bytes())
|
||||
require.True(t, curve.IsOnCurve(nil, newY))
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
// Feldman Verifiable Secret Sharing Scheme
|
||||
type Feldman struct {
|
||||
threshold, limit uint32
|
||||
curve elliptic.Curve
|
||||
}
|
||||
|
||||
// FeldmanResult contains all the data from calling Split
|
||||
type FeldmanResult struct {
|
||||
SecretShares []*ShamirShare
|
||||
Verifiers []*ShareVerifier
|
||||
}
|
||||
|
||||
func NewFeldman(threshold, limit uint32, curve elliptic.Curve) (*Feldman, error) {
|
||||
if limit < threshold {
|
||||
return nil, fmt.Errorf("limit cannot be less than threshold")
|
||||
}
|
||||
if threshold < 2 {
|
||||
return nil, fmt.Errorf("threshold must be at least 2")
|
||||
}
|
||||
return &Feldman{
|
||||
threshold, limit, curve,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f Feldman) Split(secret []byte) ([]*ShareVerifier, []*ShamirShare, error) {
|
||||
field := curves.NewField(f.curve.Params().N)
|
||||
shamir := Shamir{f.threshold, f.limit, field}
|
||||
shares, poly, err := shamir.GetSharesAndPolynomial(secret)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// Generate the verifiable commitments to the polynomial for the shares
|
||||
verifiers := make([]*ShareVerifier, len(poly.Coefficients))
|
||||
for i, c := range poly.Coefficients {
|
||||
v, err := curves.NewScalarBaseMult(f.curve, c.Value)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
verifiers[i] = v
|
||||
}
|
||||
return verifiers, shares, nil
|
||||
}
|
||||
|
||||
func (f Feldman) Combine(shares ...*ShamirShare) ([]byte, error) {
|
||||
field := curves.NewField(f.curve.Params().N)
|
||||
shamir := Shamir{f.threshold, f.limit, field}
|
||||
return shamir.Combine(shares...)
|
||||
}
|
||||
|
||||
// Verify checks a share for validity
|
||||
func (f Feldman) Verify(share *ShamirShare, verifiers []*ShareVerifier) (bool, error) {
|
||||
if len(verifiers) < int(f.threshold) {
|
||||
return false, fmt.Errorf("not enough verifiers to check")
|
||||
}
|
||||
field := curves.NewField(f.curve.Params().N)
|
||||
|
||||
xBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(xBytes, share.Identifier)
|
||||
x := field.ElementFromBytes(xBytes)
|
||||
|
||||
i := share.Value.Modulus.One()
|
||||
|
||||
// c_0
|
||||
rhs := verifiers[0]
|
||||
|
||||
// Compute the sum of products
|
||||
// c_0 * c_1^i * c_2^{i^2} * c_3^{i^3} ... c_t^{i_t}
|
||||
for j := 1; j < len(verifiers); j++ {
|
||||
// i *= x
|
||||
i = i.Mul(x)
|
||||
|
||||
c, err := verifiers[j].ScalarMult(i.Value)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// ... * c_j^{i^j}
|
||||
rhs, err = rhs.Add(c)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
lhs, err := curves.NewScalarBaseMult(f.curve, share.Value.Value)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Check if lhs == rhs
|
||||
return lhs.Equals(rhs), nil
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestK256FeldmanSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewFeldman(0, 0, btcec.S256())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(3, 2, btcec.S256())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(1, 10, btcec.S256())
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewFeldman(2, 3, btcec.S256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, _, err = scheme.Split([]byte{})
|
||||
require.NotNil(t, err)
|
||||
_, _, err = scheme.Split([]byte{0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65})
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestK256FeldmanCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, btcec.S256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestK256FeldmanCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, btcec.S256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestK256FeldmanCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, btcec.S256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Identifier: 0,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 2,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Identifier: 4,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestK256FeldmanCombineSingle(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, btcec.S256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
verifiers, shares, err := scheme.Split([]byte("test"))
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
secret, err := scheme.Combine(shares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret, []byte("test"))
|
||||
}
|
||||
|
||||
func TestK256FeldmanAllCombinations(t *testing.T) {
|
||||
scheme, err := NewFeldman(3, 5, btcec.S256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := []byte("test")
|
||||
verifiers, shares, err := scheme.Split(secret)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(shares[i], shares[j], shares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/btcsuite/btcd/btcec/v2"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
core "github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
var (
|
||||
k256BasePoint = &core.EcPoint{Curve: btcec.S256(), X: btcec.S256().Gx, Y: btcec.S256().Gy}
|
||||
testPointK256, _ = core.NewScalarBaseMult(btcec.S256(), big.NewInt(2222))
|
||||
)
|
||||
|
||||
func TestK256PedersenSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewPedersen(0, 0, nil)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewPedersen(3, 2, nil)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewPedersen(1, 10, nil)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewPedersen(2, 3, nil)
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewPedersen(2, 3, k256BasePoint)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Split([]byte{})
|
||||
require.NotNil(t, err)
|
||||
// test that split doesn't work on secrets bigger than the modulus
|
||||
_, err = scheme.Split([]byte{0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65})
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestK256PedersenCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewPedersen(2, 3, k256BasePoint)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestK256PedersenCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewPedersen(2, 3, k256BasePoint)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestK256PedersenCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewPedersen(2, 3, k256BasePoint)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Identifier: 0,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 2,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Identifier: 4,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
func TestK256GeneratorFromHashedBytes(t *testing.T) {
|
||||
x, y, err := K256GeneratorFromHashedBytes([]byte("Fair is foul, and foul is fair: Hover through the fog and filthy air."))
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, x)
|
||||
require.NotNil(t, y)
|
||||
require.True(t, btcec.S256().IsOnCurve(x, y))
|
||||
}
|
||||
|
||||
func TestK256PedersenCombineSingle(t *testing.T) {
|
||||
scheme, err := NewPedersen(2, 3, testPointK256)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
result, err := scheme.Split([]byte("test"))
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, result)
|
||||
for i, s := range result.SecretShares {
|
||||
ok, err := scheme.Verify(s, result.BlindingShares[i], result.BlindedVerifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
secret, err := scheme.Combine(result.SecretShares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret, []byte("test"))
|
||||
}
|
||||
|
||||
func TestK256PedersenAllCombinations(t *testing.T) {
|
||||
scheme, err := NewPedersen(3, 5, testPointK256)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := []byte("test")
|
||||
result, err := scheme.Split(secret)
|
||||
for i, s := range result.SecretShares {
|
||||
ok, err := scheme.Verify(s, result.BlindingShares[i], result.BlindedVerifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, result)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(result.SecretShares[i], result.SecretShares[j], result.SecretShares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
|
||||
bSecret, err := scheme.Combine(result.BlindingShares[i], result.BlindingShares[j], result.BlindingShares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, bSecret)
|
||||
require.Equal(t, bSecret, result.Blinding.Bytes())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestP256FeldmanSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewFeldman(0, 0, elliptic.P256())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(3, 2, elliptic.P256())
|
||||
require.NotNil(t, err)
|
||||
_, err = NewFeldman(1, 10, elliptic.P256())
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewFeldman(2, 3, elliptic.P256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, _, err = scheme.Split([]byte{})
|
||||
require.NotNil(t, err)
|
||||
_, _, err = scheme.Split([]byte{0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65})
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestP256FeldmanCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, elliptic.P256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestP256FeldmanCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, elliptic.P256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestP256FeldmanCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, elliptic.P256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Identifier: 0,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 2,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Identifier: 4,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestP256FeldmanCombineSingle(t *testing.T) {
|
||||
scheme, err := NewFeldman(2, 3, elliptic.P256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
verifiers, shares, err := scheme.Split([]byte("test"))
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
secret, err := scheme.Combine(shares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret, []byte("test"))
|
||||
}
|
||||
|
||||
func TestP256FeldmanAllCombinations(t *testing.T) {
|
||||
scheme, err := NewFeldman(3, 5, elliptic.P256())
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := []byte("test")
|
||||
verifiers, shares, err := scheme.Split(secret)
|
||||
for _, s := range shares {
|
||||
ok, err := scheme.Verify(s, verifiers)
|
||||
require.Nil(t, err)
|
||||
require.True(t, ok)
|
||||
}
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(shares[i], shares[j], shares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,174 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
crand "crypto/rand"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
"github.com/onsonr/sonr/crypto/internal"
|
||||
)
|
||||
|
||||
// Pedersen Verifiable Secret Sharing Scheme
|
||||
type Pedersen struct {
|
||||
threshold, limit uint32
|
||||
generator *curves.EcPoint
|
||||
}
|
||||
|
||||
// PedersenResult contains all the data from calling Split
|
||||
type PedersenResult struct {
|
||||
Blinding *big.Int
|
||||
BlindingShares, SecretShares []*ShamirShare
|
||||
BlindedVerifiers []*ShareVerifier
|
||||
Verifiers []*ShareVerifier
|
||||
}
|
||||
|
||||
// NewPedersen creates a new pedersen VSS
|
||||
func NewPedersen(threshold, limit uint32, generator *curves.EcPoint) (*Pedersen, error) {
|
||||
if limit < threshold {
|
||||
return nil, fmt.Errorf("limit cannot be less than threshold")
|
||||
}
|
||||
if threshold < 2 {
|
||||
return nil, fmt.Errorf("threshold must be at least 2")
|
||||
}
|
||||
|
||||
if generator == nil {
|
||||
return nil, internal.ErrNilArguments
|
||||
}
|
||||
if generator.IsIdentity() {
|
||||
return nil, fmt.Errorf("generator point cannot be at infinity")
|
||||
}
|
||||
if !generator.IsOnCurve() {
|
||||
return nil, fmt.Errorf("generator point must be on the curve")
|
||||
}
|
||||
|
||||
return &Pedersen{
|
||||
threshold, limit, generator,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Split creates the verifiers, blinding and shares
|
||||
func (pd Pedersen) Split(secret []byte) (*PedersenResult, error) {
|
||||
// generate a random blinding factor
|
||||
blinding, err := crand.Int(crand.Reader, pd.generator.Curve.Params().N)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
field := curves.NewField(pd.generator.Curve.Params().N)
|
||||
shamir := Shamir{pd.threshold, pd.limit, field}
|
||||
// split the secret into shares
|
||||
shares, polySecret, err := shamir.GetSharesAndPolynomial(secret)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// split the blinding into shares
|
||||
blindingShares, polyBlinding, err := shamir.GetSharesAndPolynomial(blinding.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Generate the verifiable commitments to the polynomial for the shares
|
||||
blindedverifiers := make([]*ShareVerifier, pd.threshold)
|
||||
verifiers := make([]*ShareVerifier, pd.threshold)
|
||||
|
||||
// ({p0 * G + b0 * H}, ...,{pt * G + bt * H})
|
||||
for i, c := range polySecret.Coefficients {
|
||||
s, err := curves.NewScalarBaseMult(pd.generator.Curve, c.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err := pd.generator.ScalarMult(polyBlinding.Coefficients[i].Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bv, err := s.Add(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
blindedverifiers[i] = bv
|
||||
verifiers[i] = s
|
||||
}
|
||||
return &PedersenResult{
|
||||
blinding, blindingShares, shares, blindedverifiers, verifiers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Combine recreates the original secret from the shares
|
||||
func (pd Pedersen) Combine(shares ...*ShamirShare) ([]byte, error) {
|
||||
field := curves.NewField(pd.generator.Curve.Params().N)
|
||||
shamir := Shamir{pd.threshold, pd.limit, field}
|
||||
return shamir.Combine(shares...)
|
||||
}
|
||||
|
||||
// Verify checks a share for validity
|
||||
func (pd Pedersen) Verify(share *ShamirShare, blinding *ShamirShare, blindedverifiers []*ShareVerifier) (bool, error) {
|
||||
if len(blindedverifiers) < int(pd.threshold) {
|
||||
return false, fmt.Errorf("not enough blindedverifiers to check")
|
||||
}
|
||||
field := curves.NewField(pd.generator.Curve.Params().N)
|
||||
|
||||
xBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(xBytes, share.Identifier)
|
||||
x := field.ElementFromBytes(xBytes)
|
||||
|
||||
i := share.Value.Modulus.One()
|
||||
|
||||
// c_0
|
||||
rhs := blindedverifiers[0]
|
||||
|
||||
// Compute the sum of products
|
||||
// c_0 * c_1^i * c_2^{i^2} * c_3^{i^3} ... c_t^{i_t}
|
||||
for j := 1; j < len(blindedverifiers); j++ {
|
||||
// i *= x
|
||||
i = i.Mul(x)
|
||||
|
||||
c, err := blindedverifiers[j].ScalarMult(i.Value)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// ... * c_j^{i^j}
|
||||
rhs, err = rhs.Add(c)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
lhs, err := curves.NewScalarBaseMult(pd.generator.Curve, share.Value.Value)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
tmp, err := pd.generator.ScalarMult(blinding.Value.Value)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
lhs, err = lhs.Add(tmp)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Check if lhs == rhs
|
||||
return lhs.Equals(rhs), nil
|
||||
}
|
||||
|
||||
// K256GeneratorFromHashedBytes computes a generator whose discrete log is unknown
|
||||
// from a bytes sequence
|
||||
func K256GeneratorFromHashedBytes(bytes []byte) (x, y *big.Int, err error) {
|
||||
pt := new(curves.PointK256).Hash(bytes)
|
||||
p, _ := pt.(*curves.PointK256)
|
||||
x = p.X().BigInt()
|
||||
y = p.Y().BigInt()
|
||||
err = nil
|
||||
return
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
type polynomial struct {
|
||||
Coefficients []*curves.Element
|
||||
}
|
||||
|
||||
// newPoly creates a random polynomial of the given degree but with the provided intercept value
|
||||
func newPoly(intercept *curves.Element, degree uint32) (polynomial, error) {
|
||||
p := polynomial{
|
||||
Coefficients: make([]*curves.Element, degree),
|
||||
}
|
||||
|
||||
// Intercept is the value to be split
|
||||
p.Coefficients[0] = intercept
|
||||
|
||||
// random coefficients
|
||||
for i := uint32(1); i < degree; i++ {
|
||||
c, err := intercept.Field().RandomElement(nil)
|
||||
if err != nil {
|
||||
return p, err
|
||||
}
|
||||
p.Coefficients[i] = c
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// evaluate returns the value of the polynomial for the given x
|
||||
func (p polynomial) evaluate(x *curves.Element) *curves.Element {
|
||||
// Compute the polynomial value using Horner's Method
|
||||
|
||||
degree := len(p.Coefficients) - 1
|
||||
result := p.Coefficients[degree].Clone()
|
||||
for i := degree - 1; i >= 0; i-- {
|
||||
result = result.Mul(x).Add(p.Coefficients[i])
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewPoly(t *testing.T) {
|
||||
secret := field.ElementFromBytes([]byte("test"))
|
||||
|
||||
poly, err := newPoly(secret, 4)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, poly)
|
||||
|
||||
require.Equal(t, poly.Coefficients[0], secret)
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
// ShamirShare is the data from splitting a secret
|
||||
type ShamirShare struct {
|
||||
// x-coordinate
|
||||
Identifier uint32 `json:"identifier"`
|
||||
// y-coordinate
|
||||
Value *curves.Element `json:"value"`
|
||||
}
|
||||
|
||||
// NewShamirShare creates a ShamirShare given the Identifier, value, and Field for the value
|
||||
func NewShamirShare(x uint32, y []byte, f *curves.Field) *ShamirShare {
|
||||
return &ShamirShare{
|
||||
Identifier: x,
|
||||
Value: f.ElementFromBytes(y),
|
||||
}
|
||||
}
|
||||
|
||||
// Bytes returns the representation of the share in bytes with the identifier as the first
|
||||
// 4 bytes
|
||||
func (s ShamirShare) Bytes() []byte {
|
||||
a := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(a, s.Identifier)
|
||||
a = append(a, s.Value.Bytes()...)
|
||||
return a
|
||||
}
|
||||
|
||||
// Add returns the sum of two Shamir shares
|
||||
func (s ShamirShare) Add(other *ShamirShare) *ShamirShare {
|
||||
if s.Identifier != other.Identifier {
|
||||
panic("identifiers must match for valid addition")
|
||||
}
|
||||
newSecret := s.Value.Add(other.Value)
|
||||
return NewShamirShare(s.Identifier, newSecret.Bytes(), s.Value.Field())
|
||||
}
|
||||
|
||||
// Shamir is the Shamir secret sharing scheme
|
||||
type Shamir struct {
|
||||
threshold, limit uint32
|
||||
field *curves.Field
|
||||
}
|
||||
|
||||
// NewShamir creates a Shamir secret sharing scheme
|
||||
func NewShamir(threshold, limit int, field *curves.Field) (*Shamir, error) {
|
||||
if limit < threshold {
|
||||
return nil, fmt.Errorf("limit cannot be less than threshold")
|
||||
}
|
||||
if threshold < 2 {
|
||||
return nil, fmt.Errorf("threshold must be at least 2")
|
||||
}
|
||||
return &Shamir{
|
||||
uint32(threshold), uint32(limit), field,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Split takes a secret and splits it into multiple shares that requires
|
||||
// threshold to reconstruct
|
||||
func (s *Shamir) Split(secret []byte) ([]*ShamirShare, error) {
|
||||
shares, _, err := s.GetSharesAndPolynomial(secret)
|
||||
return shares, err
|
||||
}
|
||||
|
||||
// Combine takes any number of shares and tries to combine them into the original secret
|
||||
func (s *Shamir) Combine(shares ...*ShamirShare) ([]byte, error) {
|
||||
if len(shares) < int(s.threshold) {
|
||||
return nil, fmt.Errorf("not enough shares to combine")
|
||||
}
|
||||
|
||||
dups := make(map[uint32]bool)
|
||||
xCoordinates := make([]*curves.Element, s.threshold)
|
||||
yCoordinates := make([]*curves.Element, s.threshold)
|
||||
|
||||
for i := 0; i < int(s.threshold); i++ {
|
||||
r := shares[i]
|
||||
if r.Identifier > s.limit || r.Identifier < 1 {
|
||||
return nil, fmt.Errorf("invalid share identifier")
|
||||
}
|
||||
if _, ok := dups[r.Identifier]; ok {
|
||||
return nil, fmt.Errorf("duplicate shares cannot be used")
|
||||
}
|
||||
|
||||
xBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(xBytes, r.Identifier)
|
||||
xCoordinates[i] = s.field.ElementFromBytes(xBytes)
|
||||
yCoordinates[i] = r.Value
|
||||
}
|
||||
|
||||
secret, err := s.Interpolate(xCoordinates, yCoordinates)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return secret.Bytes(), nil
|
||||
}
|
||||
|
||||
// getSharesAndPolynomial returns the shares for the specified secret and the polynomial
|
||||
// used to create the shares
|
||||
func (s *Shamir) GetSharesAndPolynomial(secret []byte) ([]*ShamirShare, *polynomial, error) {
|
||||
if len(secret) == 0 {
|
||||
return nil, nil, fmt.Errorf("cannot split an empty secret")
|
||||
}
|
||||
intSecret := new(big.Int).SetBytes(secret)
|
||||
if !s.field.IsValid(intSecret) {
|
||||
return nil, nil, fmt.Errorf("secret is too large")
|
||||
}
|
||||
|
||||
elemSecret := s.field.NewElement(intSecret)
|
||||
poly, err := newPoly(elemSecret, s.threshold)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to generate polynomial: %w", err)
|
||||
}
|
||||
|
||||
shares := make([]*ShamirShare, s.limit)
|
||||
for i := uint32(0); i < s.limit; i++ {
|
||||
x := s.field.NewElement(big.NewInt(int64(i + 1)))
|
||||
y := poly.evaluate(x)
|
||||
shares[i] = &ShamirShare{
|
||||
Identifier: i + 1,
|
||||
Value: y,
|
||||
}
|
||||
}
|
||||
return shares, &poly, nil
|
||||
}
|
||||
|
||||
// interpolate calculates the lagrange interpolation
|
||||
func (s *Shamir) Interpolate(xCoordinates, yCoordinates []*curves.Element) (*curves.Element, error) {
|
||||
if len(xCoordinates) < int(s.threshold) ||
|
||||
len(yCoordinates) < int(s.threshold) {
|
||||
return nil, fmt.Errorf("not enough points")
|
||||
}
|
||||
|
||||
zero := xCoordinates[0].Field().Zero()
|
||||
result := yCoordinates[0].Field().Zero()
|
||||
|
||||
for i := 0; i < int(s.threshold); i++ {
|
||||
basis := xCoordinates[0].Field().One()
|
||||
for j := 0; j < int(s.threshold); j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
|
||||
// x_m - x_j
|
||||
denom := xCoordinates[j].Sub(xCoordinates[i])
|
||||
if denom.IsEqual(zero) {
|
||||
return nil, fmt.Errorf("invalid x coordinates")
|
||||
}
|
||||
// x_m / x_m - x_j
|
||||
basis = basis.Mul(xCoordinates[j].Div(denom))
|
||||
}
|
||||
|
||||
result = result.Add(yCoordinates[i].Mul(basis))
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// ComputeL is a function that computes all Lagrange coefficients.
|
||||
// This function is particularly needed in FROST tSchnorr signature.
|
||||
func (s Shamir) ComputeL(shares ...*ShamirShare) ([]*curves.Element, error) {
|
||||
if len(shares) < int(s.threshold) {
|
||||
return nil, fmt.Errorf("Not enough shares to compute Lagrange coefficients")
|
||||
}
|
||||
dups := make(map[uint32]bool)
|
||||
xCoordinates := make([]*curves.Element, s.threshold)
|
||||
for i := 0; i < int(s.threshold); i++ {
|
||||
r := shares[i]
|
||||
if r.Identifier > s.limit || r.Identifier < 1 {
|
||||
return nil, fmt.Errorf("ComputeL: invalid share identifier")
|
||||
}
|
||||
if _, ok := dups[r.Identifier]; ok {
|
||||
return nil, fmt.Errorf("ComputeL: duplicate shares cannot be used")
|
||||
}
|
||||
|
||||
xBytes := make([]byte, 4)
|
||||
binary.BigEndian.PutUint32(xBytes, r.Identifier)
|
||||
xCoordinates[i] = s.field.ElementFromBytes(xBytes)
|
||||
}
|
||||
|
||||
zero := xCoordinates[0].Field().Zero()
|
||||
result := make([]*curves.Element, s.threshold)
|
||||
|
||||
for i := 0; i < int(s.threshold); i++ {
|
||||
basis := xCoordinates[0].Field().One()
|
||||
for j := 0; j < int(s.threshold); j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
// x_m - x_j
|
||||
denom := xCoordinates[j].Sub(xCoordinates[i])
|
||||
if denom.IsEqual(zero) {
|
||||
return nil, fmt.Errorf("invalid x coordinates")
|
||||
}
|
||||
// x_m / x_m - x_j
|
||||
basis = basis.Mul(xCoordinates[j].Div(denom))
|
||||
}
|
||||
result[i] = basis
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
@@ -1,205 +0,0 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/onsonr/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
func TestShamirSplitInvalidArgs(t *testing.T) {
|
||||
_, err := NewShamir(0, 0, field)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewShamir(3, 2, field)
|
||||
require.NotNil(t, err)
|
||||
_, err = NewShamir(1, 10, field)
|
||||
require.NotNil(t, err)
|
||||
scheme, err := NewShamir(2, 3, field)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Split([]byte{})
|
||||
require.NotNil(t, err)
|
||||
_, err = scheme.Split([]byte{0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65})
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestShamirCombineNoShares(t *testing.T) {
|
||||
scheme, err := NewShamir(2, 3, field)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine()
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestShamirCombineDuplicateShare(t *testing.T) {
|
||||
scheme, err := NewShamir(2, 3, field)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
_, err = scheme.Combine([]*ShamirShare{
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 1,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestShamirCombineBadIdentifier(t *testing.T) {
|
||||
scheme, err := NewShamir(2, 3, field)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
shares := []*ShamirShare{
|
||||
{
|
||||
Identifier: 0,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
{
|
||||
Identifier: 2,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
},
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
shares[0] = &ShamirShare{
|
||||
Identifier: 4,
|
||||
Value: field.NewElement(big.NewInt(3)),
|
||||
}
|
||||
_, err = scheme.Combine(shares...)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestShamirCombineSingle(t *testing.T) {
|
||||
scheme, err := NewShamir(2, 3, field)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
shares, err := scheme.Split([]byte("test"))
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
secret, err := scheme.Combine(shares...)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, secret, []byte("test"))
|
||||
}
|
||||
|
||||
// Test ComputeL function to compute Lagrange coefficients.
|
||||
func TestShamirComputeL(t *testing.T) {
|
||||
scheme, err := NewShamir(2, 2, field)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
secret := []byte("test")
|
||||
shares, err := scheme.Split(secret)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
lCoeffs, err := scheme.ComputeL(shares[0], shares[1])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, lCoeffs)
|
||||
|
||||
// Checking we can reconstruct the same secret using Lagrange coefficients.
|
||||
inputShares := [2]*ShamirShare{shares[0], shares[1]}
|
||||
yCoordinates := make([]*curves.Element, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
r := inputShares[i]
|
||||
yCoordinates[i] = r.Value
|
||||
}
|
||||
result := yCoordinates[0].Field().Zero()
|
||||
for i := 0; i < 2; i++ {
|
||||
result = result.Add(yCoordinates[i].Mul(lCoeffs[i]))
|
||||
}
|
||||
require.Equal(t, result.Bytes(), secret)
|
||||
}
|
||||
|
||||
func TestShamirAllCombinations(t *testing.T) {
|
||||
scheme, err := NewShamir(3, 5, field)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, scheme)
|
||||
|
||||
secret := []byte("test")
|
||||
shares, err := scheme.Split(secret)
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, shares)
|
||||
// There are 5*4*3 possible combinations
|
||||
for i := 0; i < 5; i++ {
|
||||
for j := 0; j < 5; j++ {
|
||||
if i == j {
|
||||
continue
|
||||
}
|
||||
for k := 0; k < 5; k++ {
|
||||
if i == k || j == k {
|
||||
continue
|
||||
}
|
||||
|
||||
rSecret, err := scheme.Combine(shares[i], shares[j], shares[k])
|
||||
require.Nil(t, err)
|
||||
require.NotNil(t, rSecret)
|
||||
require.Equal(t, rSecret, secret)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensures that ShamirShare's un/marshal successfully.
|
||||
func TestMarshalJsonRoundTrip(t *testing.T) {
|
||||
oneBelowModulus := new(big.Int).Sub(modulus, big.NewInt(1))
|
||||
shares := []ShamirShare{
|
||||
{0, field.NewElement(big.NewInt(300))},
|
||||
{2, field.NewElement(big.NewInt(300000))},
|
||||
{20, field.NewElement(big.NewInt(12812798))},
|
||||
{31, field.NewElement(big.NewInt(17))},
|
||||
{57, field.NewElement(big.NewInt(5066680))},
|
||||
{128, field.NewElement(big.NewInt(3005))},
|
||||
{19, field.NewElement(big.NewInt(317))},
|
||||
{7, field.NewElement(big.NewInt(323))},
|
||||
{222, field.NewElement(oneBelowModulus)},
|
||||
}
|
||||
// Run all the tests!
|
||||
for _, in := range shares {
|
||||
bytes, err := json.Marshal(in)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, bytes)
|
||||
|
||||
// Unmarshal and test
|
||||
out := &ShamirShare{}
|
||||
err = json.Unmarshal(bytes, &out)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, in.Identifier, out.Identifier)
|
||||
require.Equal(t, in.Value.Value.Bytes(), out.Value.Value.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSharesAdd(t *testing.T) {
|
||||
finiteField := curves.NewField(big.NewInt(7))
|
||||
one := NewShamirShare(0, []byte{0x01}, finiteField)
|
||||
two := NewShamirShare(0, []byte{0x02}, finiteField)
|
||||
|
||||
// basic addition
|
||||
sum := one.Add(two)
|
||||
require.Equal(t, uint32(0), sum.Identifier)
|
||||
require.Equal(t, []byte{0x03}, sum.Value.Bytes())
|
||||
|
||||
// addition is performed within the globalField
|
||||
sum = two.Add(NewShamirShare(0, []byte{0x06}, finiteField))
|
||||
require.Equal(t, uint32(0), sum.Identifier)
|
||||
require.Equal(t, []byte{0x01}, sum.Value.Bytes())
|
||||
}
|
||||
|
||||
func TestSharesAdd_errors(t *testing.T) {
|
||||
finiteField := curves.NewField(big.NewInt(7))
|
||||
one := NewShamirShare(0, []byte{0x01}, finiteField)
|
||||
two := NewShamirShare(1, []byte{0x02}, finiteField)
|
||||
require.PanicsWithValue(t, "identifiers must match for valid addition", func() {
|
||||
one.Add(two)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user