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:
Prad Nukala
2024-12-24 16:10:20 +00:00
committed by GitHub
parent 0ec2f7d86a
commit 47c3a53080
356 changed files with 402 additions and 1613 deletions
-16
View File
@@ -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>
-132
View File
@@ -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)
}
}
}
}
-112
View File
@@ -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...)
}
-152
View File
@@ -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...)
}
-35
View File
@@ -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
}
-32
View File
@@ -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)
}
-206
View File
@@ -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
}
-186
View File
@@ -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)
}
}
}
}
-109
View File
@@ -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)
}
}
}
}
-108
View File
@@ -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
}
-14
View File
@@ -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
-131
View File
@@ -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)
}
}
}
}
-154
View File
@@ -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())
}
}
}
}
-143
View File
@@ -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()))
}
-26
View File
@@ -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))
}
-107
View File
@@ -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
}
-132
View File
@@ -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)
}
}
}
}
-155
View File
@@ -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())
}
}
}
}
-132
View File
@@ -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)
}
}
}
}
-174
View File
@@ -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
}
-49
View File
@@ -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
}
-29
View File
@@ -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)
}
-212
View File
@@ -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
}
-205
View File
@@ -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)
})
}