mirror of
https://github.com/sonr-io/crypto.git
synced 2026-08-02 23:41:37 +00:00
No commit suggestions generated
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
//
|
||||
// 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/sonr-io/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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/sonr-io/sonr/crypto/core/curves/native"
|
||||
"github.com/sonr-io/sonr/crypto/core/curves/native/bls12381"
|
||||
"github.com/sonr-io/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
|
||||
}
|
||||
Executable
+167
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"sync"
|
||||
|
||||
"github.com/sonr-io/sonr/crypto/core/curves/native"
|
||||
"github.com/sonr-io/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
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
kryptology "github.com/sonr-io/sonr/crypto/core/curves"
|
||||
)
|
||||
|
||||
// ShareVerifier is used to verify secret shares from Feldman or Pedersen VSS
|
||||
type ShareVerifier = kryptology.EcPoint
|
||||
Executable
+167
@@ -0,0 +1,167 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
//
|
||||
// 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/sonr-io/sonr/crypto/core/curves"
|
||||
"github.com/sonr-io/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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// 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/sonr-io/sonr/crypto/core/curves"
|
||||
"github.com/sonr-io/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()))
|
||||
}
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// 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))
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"crypto/elliptic"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/sonr-io/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
|
||||
}
|
||||
Executable
+168
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
//
|
||||
// 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/sonr-io/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())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+168
@@ -0,0 +1,168 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
//
|
||||
// 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/sonr-io/sonr/crypto/core/curves"
|
||||
"github.com/sonr-io/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 x, y, err
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/sonr-io/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
|
||||
}
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
//
|
||||
// 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)
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
//
|
||||
// Copyright Coinbase, Inc. All Rights Reserved.
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/sonr-io/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
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
//
|
||||
// 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/sonr-io/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