No commit suggestions generated

This commit is contained in:
Prad Nukala
2025-10-09 15:10:39 -04:00
commit a934caa7d3
323 changed files with 98121 additions and 0 deletions
+179
View File
@@ -0,0 +1,179 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
// Package accumulator implements the cryptographic accumulator as described in https://eprint.iacr.org/2020/777.pdf
// It also implements the zero knowledge proof of knowledge protocol
// described in section 7 of the paper.
// Note: the paper only describes for non-membership witness case, but we don't
// use non-membership witness. We only implement the membership witness case.
package accumulator
import (
"fmt"
"git.sr.ht/~sircmpwn/go-bare"
"github.com/sonr-io/sonr/crypto/core/curves"
)
type structMarshal struct {
Curve string `bare:"curve"`
Value []byte `bare:"value"`
}
type Element curves.Scalar
// Coefficient is a point
type Coefficient curves.Point
// Accumulator is a point
type Accumulator struct {
value curves.Point
}
// New creates a new accumulator.
func (acc *Accumulator) New(curve *curves.PairingCurve) (*Accumulator, error) {
// If we need to support non-membership witness, we need to implement Accumulator Initialization
// as described in section 6 of <https://eprint.iacr.org/2020/777.pdf>
// for now we don't need non-membership witness
// i.e., it computes V0 = prod(y + α) * P, y ∈ Y_V0, P is a generator of G1. Since we do not use non-membership witness
// we just set the initial accumulator a G1 generator.
acc.value = curve.Scalar.Point().Generator()
return acc, nil
}
// WithElements initializes a new accumulator prefilled with entries
// Each member is assumed to be hashed
// V = prod(y + α) * V0, for all y∈ Y_V
func (acc *Accumulator) WithElements(
curve *curves.PairingCurve,
key *SecretKey,
m []Element,
) (*Accumulator, error) {
_, err := acc.New(curve)
if err != nil {
return nil, err
}
y, err := key.BatchAdditions(m)
if err != nil {
return nil, err
}
acc.value = acc.value.Mul(y)
return acc, nil
}
// AddElements accumulates a set of elements into the accumulator.
func (acc *Accumulator) AddElements(key *SecretKey, m []Element) (*Accumulator, error) {
if acc.value == nil || key.value == nil {
return nil, fmt.Errorf("accumulator and secret key should not be nil")
}
y, err := key.BatchAdditions(m)
if err != nil {
return nil, err
}
acc.value = acc.value.Mul(y)
return acc, nil
}
// Add accumulates a single element into the accumulator
// V' = (y + alpha) * V
func (acc *Accumulator) Add(key *SecretKey, e Element) (*Accumulator, error) {
if acc.value == nil || acc.value.IsIdentity() || key.value == nil || e == nil {
return nil, fmt.Errorf("accumulator, secret key and element should not be nil")
}
y := e.Add(key.value) // y + alpha
acc.value = acc.value.Mul(y)
return acc, nil
}
// Remove removes a single element from accumulator if it exists
// V' = 1/(y+alpha) * V
func (acc *Accumulator) Remove(key *SecretKey, e Element) (*Accumulator, error) {
if acc.value == nil || acc.value.IsIdentity() || key.value == nil || e == nil {
return nil, fmt.Errorf("accumulator, secret key and element should not be nil")
}
y := e.Add(key.value) // y + alpha
y, err := y.Invert() // 1/(y+alpha)
if err != nil {
return nil, err
}
acc.value = acc.value.Mul(y)
return acc, nil
}
// Update performs a batch addition and deletion as described on page 7, section 3 in
// https://eprint.iacr.org/2020/777.pdf
func (acc *Accumulator) Update(
key *SecretKey,
additions []Element,
deletions []Element,
) (*Accumulator, []Coefficient, error) {
if acc.value == nil || acc.value.IsIdentity() || key.value == nil {
return nil, nil, fmt.Errorf("accumulator and secret key should not be nil")
}
// Compute dA(-alpha) = prod(y + alpha), y in the set of A ⊆ ACC-Y_V
a, err := key.BatchAdditions(additions)
if err != nil {
return nil, nil, err
}
// Compute dD(-alpha) = 1/prod(y + alpha), y in the set of D ⊆ Y_V
d, err := key.BatchDeletions(deletions)
if err != nil {
return nil, nil, err
}
// dA(-alpha)/dD(-alpha)
div := a.Mul(d)
newAcc := acc.value.Mul(div)
// build an array of coefficients
elements, err := key.CreateCoefficients(additions, deletions)
if err != nil {
return nil, nil, err
}
coefficients := make([]Coefficient, len(elements))
for i := range elements {
coefficients[i] = acc.value.Mul(elements[i])
}
acc.value = newAcc
return acc, coefficients, nil
}
// MarshalBinary converts Accumulator to bytes
func (acc Accumulator) MarshalBinary() ([]byte, error) {
if acc.value == nil {
return nil, fmt.Errorf("accumulator cannot be nil")
}
tv := &structMarshal{
Value: acc.value.ToAffineCompressed(),
Curve: acc.value.CurveName(),
}
return bare.Marshal(tv)
}
// UnmarshalBinary sets Accumulator from bytes
func (acc *Accumulator) UnmarshalBinary(data []byte) error {
tv := new(structMarshal)
err := bare.Unmarshal(data, tv)
if err != nil {
return err
}
curve := curves.GetCurveByName(tv.Curve)
if curve == nil {
return fmt.Errorf("invalid curve")
}
value, err := curve.NewIdentityPoint().FromAffineCompressed(tv.Value)
if err != nil {
return err
}
acc.value = value
return nil
}
+221
View File
@@ -0,0 +1,221 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"encoding/hex"
"fmt"
"testing"
"github.com/stretchr/testify/require"
"github.com/sonr-io/sonr/crypto/core/curves"
)
func TestNewAccumulator100(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, err := new(SecretKey).New(curve, seed[:])
require.NoError(t, err)
require.NotNil(t, key)
acc, err := new(Accumulator).New(curve)
require.NoError(t, err)
accBz, err := acc.MarshalBinary()
require.NoError(t, err)
fmt.Println(accBz)
fmt.Println(len(accBz))
fmt.Println(hex.EncodeToString(accBz))
fmt.Println(len(hex.EncodeToString(accBz)))
require.Equal(t, 60, len(accBz), "Marshalled accumulator should be 60 bytes")
require.Equal(
t,
120,
len(hex.EncodeToString(accBz)),
"Hex-encoded accumulator should be 120 characters",
)
require.NotNil(t, acc)
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
}
func TestNewAccumulator10K(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, err := new(SecretKey).New(curve, seed[:])
require.NoError(t, err)
require.NotNil(t, key)
acc, err := new(Accumulator).New(curve)
require.NoError(t, err)
require.NotNil(t, acc)
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
}
func TestNewAccumulator10M(t *testing.T) {
// Initiating 10M values takes time
if testing.Short() {
t.Skip("skipping test in short mode.")
}
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, err := new(SecretKey).New(curve, seed[:])
require.NoError(t, err)
require.NotNil(t, key)
acc, err := new(Accumulator).New(curve)
require.NoError(t, err)
require.NotNil(t, acc)
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
}
func TestWithElements(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, _ := new(SecretKey).New(curve, seed[:])
element1 := curve.Scalar.Hash([]byte("value1"))
element2 := curve.Scalar.Hash([]byte("value2"))
elements := []Element{element1, element2}
newAcc, err := new(Accumulator).WithElements(curve, key, elements)
require.NoError(t, err)
require.NotNil(t, newAcc)
require.NotEqual(
t,
newAcc.value.ToAffineCompressed(),
curve.PointG1.Identity().ToAffineCompressed(),
)
require.NotEqual(
t,
newAcc.value.ToAffineCompressed(),
curve.PointG1.Generator().ToAffineCompressed(),
)
_, _ = newAcc.Remove(key, element1)
_, _ = newAcc.Remove(key, element2)
require.Equal(
t,
newAcc.value.ToAffineCompressed(),
curve.PointG1.Generator().ToAffineCompressed(),
)
}
func TestAdd(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, err := new(SecretKey).New(curve, seed[:])
require.NoError(t, err)
require.NotNil(t, key)
acc := &Accumulator{curve.PointG1.Generator()}
_, _ = acc.New(curve)
require.NoError(t, err)
require.NotNil(t, acc)
element := curve.Scalar.Hash([]byte("value1"))
require.NoError(t, err)
require.NotNil(t, element)
_, _ = acc.Add(key, element)
require.NotEqual(
t,
acc.value.ToAffineCompressed(),
curve.PointG1.Generator().ToAffineCompressed(),
)
}
func TestRemove(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, err := new(SecretKey).New(curve, seed[:])
require.NoError(t, err)
require.NotNil(t, key)
acc, err := new(Accumulator).New(curve)
require.NoError(t, err)
require.NotNil(t, acc)
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
element := curve.Scalar.Hash([]byte("value1"))
require.NoError(t, err)
require.NotNil(t, element)
// add element
_, _ = acc.Add(key, element)
require.NotEqual(
t,
acc.value.ToAffineCompressed(),
curve.PointG1.Generator().ToAffineCompressed(),
)
// remove element
acc, err = acc.Remove(key, element)
require.NoError(t, err)
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
}
func TestAddElements(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, err := new(SecretKey).New(curve, seed[:])
require.NoError(t, err)
require.NotNil(t, key)
acc := &Accumulator{curve.PointG1.Generator()}
_, _ = acc.New(curve)
require.NoError(t, err)
require.NotNil(t, acc)
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
element1 := curve.Scalar.Hash([]byte("value1"))
element2 := curve.Scalar.Hash([]byte("value2"))
element3 := curve.Scalar.Hash([]byte("value3"))
elements := []Element{element1, element2, element3}
acc, err = acc.AddElements(key, elements)
require.NoError(t, err)
require.NotEqual(
t,
acc.value.ToAffineCompressed(),
curve.PointG1.Generator().ToAffineCompressed(),
)
}
func TestAccumulatorMarshal(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
point := curve.PointG1.Generator().Mul(curve.Scalar.New(2))
data, err := Accumulator{point}.MarshalBinary()
require.NoError(t, err)
require.NotNil(t, data)
// element cannot be empty
_, err = Accumulator{}.MarshalBinary()
require.Error(t, err)
e := &Accumulator{curve.PointG1.Generator()}
_ = e.UnmarshalBinary(data)
require.True(t, e.value.Equal(point))
}
func TestUpdate(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, err := new(SecretKey).New(curve, seed[:])
require.NoError(t, err)
require.NotNil(t, key)
acc, err := new(Accumulator).New(curve)
require.NoError(t, err)
require.NotNil(t, acc)
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
element1 := curve.Scalar.Hash([]byte("value1"))
element2 := curve.Scalar.Hash([]byte("value2"))
element3 := curve.Scalar.Hash([]byte("value3"))
elements := []Element{element1, element2, element3}
acc, _, err = acc.Update(key, elements, nil)
require.NoError(t, err)
require.NotEqual(
t,
acc.value.ToAffineCompressed(),
curve.PointG1.Generator().ToAffineCompressed(),
)
acc, _, err = acc.Update(key, nil, elements)
require.NoError(t, err)
require.Equal(t, acc.value.ToAffineCompressed(), curve.PointG1.Generator().ToAffineCompressed())
}
+247
View File
@@ -0,0 +1,247 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"errors"
"fmt"
"git.sr.ht/~sircmpwn/go-bare"
"github.com/sonr-io/sonr/crypto/core/curves"
)
// SecretKey is the secret alpha only held by the accumulator manager.
type SecretKey struct {
value curves.Scalar
}
// New creates a new secret key from the seed.
func (sk *SecretKey) New(curve *curves.PairingCurve, seed []byte) (*SecretKey, error) {
sk.value = curve.Scalar.Hash(seed)
return sk, nil
}
// GetPublicKey creates a public key from SecretKey sk
func (sk SecretKey) GetPublicKey(curve *curves.PairingCurve) (*PublicKey, error) {
if sk.value == nil || curve == nil {
return nil, fmt.Errorf("curve and sk value cannot be nil")
}
value := curve.Scalar.Point().(curves.PairingPoint).OtherGroup().Generator().Mul(sk.value)
return &PublicKey{value.(curves.PairingPoint)}, nil
}
// MarshalBinary converts SecretKey to bytes
func (sk SecretKey) MarshalBinary() ([]byte, error) {
if sk.value == nil {
return nil, fmt.Errorf("sk cannot be empty")
}
tv := &structMarshal{
Value: sk.value.Bytes(),
Curve: sk.value.Point().CurveName(),
}
return bare.Marshal(tv)
}
// UnmarshalBinary sets SecretKey from bytes
func (sk *SecretKey) UnmarshalBinary(data []byte) error {
tv := new(structMarshal)
err := bare.Unmarshal(data, tv)
if err != nil {
return err
}
curve := curves.GetCurveByName(tv.Curve)
if curve == nil {
return fmt.Errorf("invalid curve")
}
value, err := curve.NewScalar().SetBytes(tv.Value)
if err != nil {
return err
}
sk.value = value
return nil
}
// BatchAdditions computes product(y + sk) for y in additions and output the product
func (sk SecretKey) BatchAdditions(additions []Element) (Element, error) {
if sk.value == nil {
return nil, fmt.Errorf("secret key cannot be empty")
}
mul := sk.value.One()
for i := 0; i < len(additions); i++ {
if additions[i] == nil {
return nil, fmt.Errorf("some element in additions is nil")
}
// y + alpha
temp := additions[i].Add(sk.value)
// prod(y + alpha)
mul = mul.Mul(temp)
}
return mul, nil
}
// BatchDeletions computes 1/product(y + sk) for y in deletions and output it
func (sk SecretKey) BatchDeletions(deletions []Element) (Element, error) {
v, err := sk.BatchAdditions(deletions)
if err != nil {
return nil, err
}
y, err := v.Invert()
if err != nil {
return nil, err
}
return y, nil
}
// CreateCoefficients creates the Batch Polynomial coefficients
// See page 7 of https://eprint.iacr.org/2020/777.pdf
func (sk SecretKey) CreateCoefficients(
additions []Element,
deletions []Element,
) ([]Element, error) {
if sk.value == nil {
return nil, fmt.Errorf("secret key should not be nil")
}
// vD(x) = ∑^{m}_{s=1}{ ∏ 1..s {yD_i + alpha}^-1 ∏ 1 ..s-1 {yD_j - x}
one := sk.value.One()
m1 := one.Neg() // m1 is -1
vD := make(polynomial, 0, len(deletions))
for s := 0; s < len(deletions); s++ {
// ∏ 1..s (yD_i + alpha)^-1
c, err := sk.BatchDeletions(deletions[0 : s+1])
if err != nil {
return nil, fmt.Errorf("error in sk batchDeletions")
}
poly := make(polynomial, 1, s+2)
poly[0] = one
// ∏ 1..(s-1) (yD_j - x)
for j := 0; j < s; j++ {
t := make(polynomial, 2)
// yD_j
t[0] = deletions[j]
// -x
t[1] = m1
// polynomial multiplication (yD_1-x) * (yD_2 - x) ...
poly, err = poly.Mul(t)
if err != nil {
return nil, err
}
}
poly, err = poly.MulScalar(c)
if err != nil {
return nil, err
}
vD, err = vD.Add(poly)
if err != nil {
return nil, err
}
}
// vD(x) * ∏ 1..n (yA_i + alpha)
bAdd, err := sk.BatchAdditions(additions)
if err != nil {
return nil, fmt.Errorf("error in sk batchAdditions")
}
vD, err = vD.MulScalar(bAdd)
if err != nil {
return nil, err
}
// vA(x) = ∑^n_{s=1}{ ∏ 1..s-1 {yA_i + alpha} ∏ s+1..n {yA_j - x} }
vA := make(polynomial, 0, len(additions))
for s := range additions {
// ∏ 1..s-1 {yA_i + alpha}
var c Element
if s == 0 {
c = one
} else {
c, err = sk.BatchAdditions(additions[0:s])
if err != nil {
return nil, err
}
}
poly := make(polynomial, 1, s+2)
poly[0] = one
// ∏ s+1..n {yA_j - x}
for j := s + 1; j < len(additions); j++ {
t := make(polynomial, 2)
t[0] = additions[j]
t[1] = m1
// polynomial multiplication (yA_1-x) * (yA_2 - x) ...
poly, err = poly.Mul(t)
if err != nil {
return nil, err
}
}
poly, err = poly.MulScalar(c)
if err != nil {
return nil, err
}
vA, err = vA.Add(poly)
if err != nil {
return nil, err
}
}
// vA - vD
vA, err = vA.Sub(vD)
if err != nil {
return nil, err
}
result := make([]Element, len(vA))
for i := 0; i < len(vA); i++ {
result[i] = vA[i]
}
return result, nil
}
// PublicKey is the public key of accumulator, it should be sk * generator of G2
type PublicKey struct {
value curves.PairingPoint
}
// MarshalBinary converts PublicKey to bytes
func (pk PublicKey) MarshalBinary() ([]byte, error) {
if pk.value == nil {
return nil, fmt.Errorf("public key cannot be nil")
}
tv := &structMarshal{
Value: pk.value.ToAffineCompressed(),
Curve: pk.value.CurveName(),
}
return bare.Marshal(tv)
}
// UnmarshalBinary sets PublicKey from bytes
func (pk *PublicKey) UnmarshalBinary(data []byte) error {
tv := new(structMarshal)
err := bare.Unmarshal(data, tv)
if err != nil {
return err
}
curve := curves.GetPairingCurveByName(tv.Curve)
if curve == nil {
return fmt.Errorf("invalid curve")
}
value, err := curve.NewScalar().Point().FromAffineCompressed(tv.Value)
if err != nil {
return err
}
var ok bool
pk.value, ok = value.(curves.PairingPoint)
if !ok {
return errors.New("can't convert to PairingPoint")
}
return nil
}
+88
View File
@@ -0,0 +1,88 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/sonr-io/sonr/crypto/core/curves"
)
func TestSecretKeyMarshal(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
data, err := SecretKey{curve.Scalar.One()}.MarshalBinary()
require.NoError(t, err)
require.NotNil(t, data)
e := &SecretKey{curve.Scalar.New(2)}
err = e.UnmarshalBinary(data)
require.NoError(t, err)
require.Equal(t, e.value.Bytes(), curve.Scalar.One().Bytes())
// element cannot be empty
_, err = SecretKey{}.MarshalBinary()
require.Error(t, err)
}
func TestPublicKeyMarshal(t *testing.T) {
// Actually test both toBytes() and from()
curve := curves.BLS12381(&curves.PointBls12381G1{})
sk := &SecretKey{curve.Scalar.New(3)}
pk, _ := sk.GetPublicKey(curve)
pkBytes, err := pk.MarshalBinary()
require.NoError(t, err)
require.NotNil(t, pkBytes)
pk2 := &PublicKey{}
err = pk2.UnmarshalBinary(pkBytes)
require.NoError(t, err)
require.True(t, pk.value.Equal(pk2.value))
}
func TestBatch(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
sk, _ := new(SecretKey).New(curve, seed[:])
element1 := curve.Scalar.Hash([]byte("value1"))
element2 := curve.Scalar.Hash([]byte("value2"))
elements := []Element{element1, element2}
add, err := sk.BatchAdditions(elements)
require.NoError(t, err)
require.NotNil(t, add)
del, err := sk.BatchDeletions(elements)
require.NoError(t, err)
require.NotNil(t, del)
result := add.Mul(del)
require.Equal(t, result, curve.Scalar.One())
g1 := curve.PointG1.Generator()
acc := g1.Mul(add)
require.NotEqual(t, acc, g1)
acc = acc.Mul(del)
require.Equal(t, acc.ToAffineCompressed(), g1.ToAffineCompressed())
acc2 := g1.Mul(result)
require.True(t, acc2.Equal(g1))
}
func TestCoefficient(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
element1 := curve.Scalar.Hash([]byte("value1"))
element2 := curve.Scalar.Hash([]byte("value2"))
element3 := curve.Scalar.Hash([]byte("value3"))
element4 := curve.Scalar.Hash([]byte("value4"))
element5 := curve.Scalar.Hash([]byte("value5"))
elements := []Element{element1, element2, element3, element4, element5}
coefficients, err := sk.CreateCoefficients(elements[0:2], elements[2:5])
require.NoError(t, err)
require.Equal(t, len(coefficients), 3)
}
+204
View File
@@ -0,0 +1,204 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"fmt"
"math"
"github.com/sonr-io/sonr/crypto/core/curves"
)
// dad constructs two polynomials - dA(x) and dD(x)
// dA(y) = prod(y_A,t - y), t = 1...n
// dD(y) = prod(y_D,t - y), t = 1...n
func dad(values []Element, y Element) (Element, error) {
if values == nil || y == nil {
return nil, fmt.Errorf("curve, values or y should not be nil")
}
for _, value := range values {
if value == nil {
return nil, fmt.Errorf("some element is nil")
}
}
result := y.One()
if len(values) == 1 {
a := values[0]
result = a.Sub(y)
} else {
for i := range values {
temp := values[i].Sub(y)
result = result.Mul(temp)
}
}
return result, nil
}
type polynomialPoint []curves.Point
// evaluate evaluates a PolynomialG1 on input x.
func (p polynomialPoint) evaluate(x curves.Scalar) (curves.Point, error) {
if p == nil {
return nil, fmt.Errorf("p cannot be empty")
}
for i := 0; i < len(p); i++ {
if p[i] == nil {
return nil, fmt.Errorf("some coefficient in p is nil")
}
}
pp := x
res := p[0]
for i := 1; i < len(p); i++ {
r := p[i].Mul(pp)
res = res.Add(r)
pp = pp.Mul(x)
}
return res, nil
}
// Add adds two PolynomialG1
func (p polynomialPoint) Add(rhs polynomialPoint) (polynomialPoint, error) {
maxLen := int(math.Max(float64(len(p)), float64(len(rhs))))
result := make(polynomialPoint, maxLen)
for i, c := range p {
if c == nil {
return nil, fmt.Errorf("invalid coefficient at %d", i)
}
result[i] = c.Add(c.Identity())
}
for i, c := range rhs {
if c == nil {
return nil, fmt.Errorf("invalid coefficient at %d", i)
}
if result[i] == nil {
result[i] = c.Add(c.Identity())
} else {
result[i] = result[i].Add(c)
}
}
return result, nil
}
// Mul for PolynomialG1 computes rhs * p, p is a polynomial, rhs is a value
func (p polynomialPoint) Mul(rhs curves.Scalar) (polynomialPoint, error) {
result := make(polynomialPoint, len(p))
for i, c := range p {
if c == nil {
return nil, fmt.Errorf("invalid coefficient at %d", i)
}
result[i] = c.Mul(rhs)
}
return result, nil
}
type polynomial []curves.Scalar
// Add adds two polynomials
func (p polynomial) Add(rhs polynomial) (polynomial, error) {
maxLen := int(math.Max(float64(len(p)), float64(len(rhs))))
result := make([]curves.Scalar, maxLen)
for i, c := range p {
if c == nil {
return nil, fmt.Errorf("invalid coefficient at %d", i)
}
result[i] = c.Clone()
}
for i, c := range rhs {
if c == nil {
return nil, fmt.Errorf("invalid coefficient at %d", i)
}
if result[i] == nil {
result[i] = c.Clone()
} else {
result[i] = result[i].Add(c)
}
}
return result, nil
}
// Sub computes p-rhs and returns
func (p polynomial) Sub(rhs polynomial) (polynomial, error) {
maxLen := int(math.Max(float64(len(p)), float64(len(rhs))))
result := make([]curves.Scalar, maxLen)
for i, c := range p {
if c == nil {
return nil, fmt.Errorf("invalid coefficient at %d", i)
}
result[i] = c.Clone()
}
for i, c := range rhs {
if c == nil {
return nil, fmt.Errorf("invalid coefficient at %d", i)
}
if result[i] == nil {
result[i] = c.Neg()
} else {
result[i] = result[i].Sub(c)
}
}
return result, nil
}
// Mul multiplies two polynomials - p * rhs
func (p polynomial) Mul(rhs polynomial) (polynomial, error) {
// Check for each coefficient that should not be nil
for i, c := range p {
if c == nil {
return nil, fmt.Errorf("coefficient in p at %d is nil", i)
}
}
for i, c := range rhs {
if c == nil {
return nil, fmt.Errorf("coefficient in rhs at %d is nil", i)
}
}
m := len(p)
n := len(rhs)
// Initialize the product polynomial
prod := make(polynomial, m+n-1)
for i := 0; i < len(prod); i++ {
prod[i] = p[0].Zero()
}
// Multiply two polynomials term by term
for i, cp := range p {
for j, cr := range rhs {
temp := cp.Mul(cr)
prod[i+j] = prod[i+j].Add(temp)
}
}
return prod, nil
}
// MulScalar computes p * rhs, where rhs is a scalar value
func (p polynomial) MulScalar(rhs curves.Scalar) (polynomial, error) {
result := make(polynomial, len(p))
for i, c := range p {
if c == nil {
return nil, fmt.Errorf("coefficient at %d is nil", i)
}
result[i] = c.Mul(rhs)
}
return result, nil
}
+404
View File
@@ -0,0 +1,404 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/sonr-io/sonr/crypto/core/curves"
)
func TestEvaluatePolyG1(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
}
output1, err := poly.evaluate(curve.Scalar.New(1))
require.NoError(t, err)
require.NotNil(t, output1)
result1 := curve.PointG1.Generator().Mul(curve.Scalar.New(6))
require.Equal(t, output1.ToAffineCompressed(), result1.ToAffineCompressed())
output2, err := poly.evaluate(curve.Scalar.New(2))
require.NoError(t, err)
require.NotNil(t, output2)
result2 := curve.PointG1.Generator().Mul(curve.Scalar.New(11))
require.Equal(t, output2.ToAffineCompressed(), result2.ToAffineCompressed())
}
func TestEvaluatePolyG1Error(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly := polynomialPoint{
nil,
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
}
_, err := poly.evaluate(curve.Scalar.New(1))
require.Error(t, err)
}
func TestAddAssignPolyG1(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
// Test polynomial with equal length
poly1 := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
}
poly2 := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
}
output, err := poly1.Add(poly2)
require.NoError(t, err)
require.NotNil(t, output)
result := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
}
for i := 0; i < len(output); i++ {
require.Equal(t, output[i].ToAffineCompressed(), result[i].ToAffineCompressed())
}
// Test polynomials with unequal length
poly3 := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
}
output2, err := poly1.Add(poly3)
require.NoError(t, err)
require.NotNil(t, output2)
result2 := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
curve.PointG1.Generator().Mul(curve.Scalar.New(4)),
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
}
require.Equal(t, len(output2), len(result2))
for i := 0; i < len(output2); i++ {
require.Equal(t, output2[i].ToAffineCompressed(), result2[i].ToAffineCompressed())
}
// Test polynomial with Capacity
poly4 := make(polynomialPoint, 0, 3)
poly5, err := poly4.Add(poly1)
require.NoError(t, err)
require.Equal(t, len(poly5), len(poly1))
for i := 0; i < len(poly5); i++ {
require.Equal(t, poly5[i].ToAffineCompressed(), poly1[i].ToAffineCompressed())
}
}
func TestAddAssignPolyG1Error(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly1 := polynomialPoint{
nil,
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
}
poly2 := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
}
output, err := poly1.Add(poly2)
require.Error(t, err)
require.Nil(t, output)
}
func TestMulAssignPolyG1(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
}
rhs := curve.Scalar.New(3)
output, err := poly.Mul(rhs)
require.NoError(t, err)
require.NotNil(t, output)
poly2 := polynomialPoint{
curve.PointG1.Generator().Mul(curve.Scalar.New(9)),
curve.PointG1.Generator().Mul(curve.Scalar.New(6)),
curve.PointG1.Generator().Mul(curve.Scalar.New(3)),
}
for i := 0; i < len(poly2); i++ {
require.Equal(t, output[i].ToAffineCompressed(), poly2[i].ToAffineCompressed())
}
}
func TestMulAssignPolyG1Error(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly := polynomialPoint{
nil,
curve.PointG1.Generator().Mul(curve.Scalar.New(2)),
curve.PointG1.Generator().Mul(curve.Scalar.New(1)),
}
rhs := curve.Scalar.New(3)
output, err := poly.Mul(rhs)
require.Error(t, err)
require.Nil(t, output)
}
func TestPushPoly(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly := polynomial{
curve.Scalar.New(3),
curve.Scalar.New(2),
curve.Scalar.New(1),
}
scalar := curve.Scalar.New(4)
result := append(poly, scalar)
require.Equal(t, result[3], scalar)
// Push one more
scalar2 := curve.Scalar.New(5)
result2 := append(result, scalar2)
require.Equal(t, result2[4], scalar2)
// Push to a new polynomial
newPoly := polynomial{}
newPoly = append(newPoly, scalar)
require.Equal(t, newPoly[0], scalar)
newPoly = append(newPoly, scalar2)
require.Equal(t, newPoly[1], scalar2)
}
func TestAddAssignPoly(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
// Test polynomial with equal length
poly1 := polynomial{
curve.Scalar.New(3),
curve.Scalar.New(2),
curve.Scalar.New(1),
}
poly2 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
curve.Scalar.New(3),
}
output, err := poly1.Add(poly2)
require.NoError(t, err)
require.NotNil(t, output)
result := []curves.Scalar{
curve.Scalar.New(4),
curve.Scalar.New(4),
curve.Scalar.New(4),
}
for i := 0; i < len(output); i++ {
require.Equal(t, output[i], result[i])
}
// Test polynomials with unequal length
poly3 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
}
output2, err := poly1.Add(poly3)
require.NoError(t, err)
require.NotNil(t, output2)
result2 := []curves.Scalar{
curve.Scalar.New(4),
curve.Scalar.New(4),
curve.Scalar.New(1),
}
require.Equal(t, len(output2), len(result2))
for i := 0; i < len(output2); i++ {
require.Equal(t, output2[i], result2[i])
}
}
func TestAddAssignPolyError(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
// Test polynomial with equal length
poly1 := polynomial{
nil,
curve.Scalar.New(2),
curve.Scalar.New(1),
}
poly2 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
curve.Scalar.New(3),
}
output, err := poly1.Add(poly2)
require.Error(t, err)
require.Nil(t, output)
}
func TestSubAssignPoly(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
// Test polynomial with equal length
poly1 := polynomial{
curve.Scalar.New(3),
curve.Scalar.New(2),
curve.Scalar.New(1),
}
poly2 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
curve.Scalar.New(3),
}
output, err := poly1.Sub(poly2)
require.NoError(t, err)
require.NotNil(t, output)
result := []curves.Scalar{
curve.Scalar.New(2),
curve.Scalar.New(0),
curve.Scalar.New(-2),
}
for i := 0; i < len(output); i++ {
require.Equal(t, output[i].Bytes(), result[i].Bytes())
}
// Test polynomials with unequal length
poly3 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
curve.Scalar.New(3),
curve.Scalar.New(4),
}
output2, err := poly1.Sub(poly3)
require.NoError(t, err)
require.NotNil(t, output2)
result2 := []curves.Scalar{
curve.Scalar.New(2),
curve.Scalar.New(0),
curve.Scalar.New(-2),
curve.Scalar.New(-4),
}
require.Equal(t, len(output2), len(result2))
for i := 0; i < len(output2); i++ {
require.Equal(t, output2[i].Bytes(), result2[i].Bytes())
}
}
func TestSubAssignPolyError(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly1 := polynomial{
nil,
curve.Scalar.New(2),
curve.Scalar.New(1),
}
poly2 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
curve.Scalar.New(3),
}
output, err := poly1.Sub(poly2)
require.Error(t, err)
require.Nil(t, output)
}
func TestMulAssignPoly(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
// Test polynomial with equal length
poly1 := polynomial{
curve.Scalar.New(3),
curve.Scalar.New(2),
curve.Scalar.New(1),
}
poly2 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
curve.Scalar.New(3),
}
output, err := poly1.Mul(poly2)
require.NoError(t, err)
require.NotNil(t, output)
result := []curves.Scalar{
curve.Scalar.New(3),
curve.Scalar.New(8),
curve.Scalar.New(14),
curve.Scalar.New(8),
curve.Scalar.New(3),
}
for i := 0; i < len(result); i++ {
require.Equal(t, output[i].Bytes(), result[i].Bytes())
}
// Test polynomials with unequal length
poly3 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
}
output2, err := poly1.Mul(poly3)
require.NoError(t, err)
require.NotNil(t, output2)
result2 := []curves.Scalar{
curve.Scalar.New(3),
curve.Scalar.New(8),
curve.Scalar.New(5),
curve.Scalar.New(2),
}
require.Equal(t, len(output2), 4)
for i := 0; i < len(output2); i++ {
require.Equal(t, output2[i].Bytes(), result2[i].Bytes())
}
}
func TestMulAssignPolyError(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly1 := polynomial{
nil,
curve.Scalar.New(2),
curve.Scalar.New(1),
}
poly2 := polynomial{
curve.Scalar.New(1),
curve.Scalar.New(2),
curve.Scalar.New(3),
}
output, err := poly1.Mul(poly2)
require.Error(t, err)
require.Nil(t, output)
}
func TestMulValueAssignPoly(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly := polynomial{
curve.Scalar.New(3),
curve.Scalar.New(2),
curve.Scalar.New(1),
}
rhs := curve.Scalar.New(3)
output, err := poly.MulScalar(rhs)
require.NoError(t, err)
require.NotNil(t, output)
coefficients2 := []curves.Scalar{
curve.Scalar.New(9),
curve.Scalar.New(6),
curve.Scalar.New(3),
}
for i := 0; i < len(coefficients2); i++ {
require.Equal(t, output[i].Bytes(), coefficients2[i].Bytes())
}
}
func TestMulValueAssignPolyError(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
poly := polynomial{
nil,
curve.Scalar.New(2),
curve.Scalar.New(1),
}
rhs := curve.Scalar.New(3)
output, err := poly.MulScalar(rhs)
require.Error(t, err)
require.Nil(t, output)
}
+527
View File
@@ -0,0 +1,527 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"bytes"
crand "crypto/rand"
"errors"
"fmt"
"git.sr.ht/~sircmpwn/go-bare"
"github.com/sonr-io/sonr/crypto/core/curves"
)
type proofParamsMarshal struct {
X []byte `bare:"x"`
Y []byte `bare:"y"`
Z []byte `bare:"z"`
Curve string `bare:"curve"`
}
// ProofParams contains four distinct public generators of G1 - X, Y, Z
type ProofParams struct {
x, y, z curves.Point
}
// New samples X, Y, Z, K
func (p *ProofParams) New(
curve *curves.PairingCurve,
pk *PublicKey,
entropy []byte,
) (*ProofParams, error) {
pkBytes, err := pk.MarshalBinary()
if err != nil {
return nil, err
}
prefix := bytes.Repeat([]byte{0xFF}, 32)
data := append(prefix, entropy...)
data = append(data, pkBytes...)
p.z = curve.Scalar.Point().Hash(data)
data[0] = 0xFE
p.y = curve.Scalar.Point().Hash(data)
data[0] = 0xFD
p.x = curve.Scalar.Point().Hash(data)
return p, nil
}
// MarshalBinary converts ProofParams to bytes
func (p *ProofParams) MarshalBinary() ([]byte, error) {
if p.x == nil || p.y == nil || p.z == nil {
return nil, fmt.Errorf("some value x, y, or z is nil")
}
tv := &proofParamsMarshal{
X: p.x.ToAffineCompressed(),
Y: p.y.ToAffineCompressed(),
Z: p.z.ToAffineCompressed(),
Curve: p.x.CurveName(),
}
return bare.Marshal(tv)
}
// UnmarshalBinary converts bytes to ProofParams
func (p *ProofParams) UnmarshalBinary(data []byte) error {
if data == nil {
return fmt.Errorf("expected non-zero byte sequence")
}
tv := new(proofParamsMarshal)
err := bare.Unmarshal(data, tv)
if err != nil {
return err
}
curve := curves.GetCurveByName(tv.Curve)
if curve == nil {
return fmt.Errorf("invalid curve")
}
x, err := curve.NewIdentityPoint().FromAffineCompressed(tv.X)
if err != nil {
return err
}
y, err := curve.NewIdentityPoint().FromAffineCompressed(tv.Y)
if err != nil {
return err
}
z, err := curve.NewIdentityPoint().FromAffineCompressed(tv.Z)
if err != nil {
return err
}
p.x = x
p.y = y
p.z = z
return nil
}
// MembershipProofCommitting contains value computed in Proof of knowledge and
// Blinding phases as described in section 7 of https://eprint.iacr.org/2020/777.pdf
type MembershipProofCommitting struct {
eC curves.Point
tSigma curves.Point
tRho curves.Point
deltaSigma curves.Scalar
deltaRho curves.Scalar
blindingFactor curves.Scalar
rSigma curves.Scalar
rRho curves.Scalar
rDeltaSigma curves.Scalar
rDeltaRho curves.Scalar
sigma curves.Scalar
rho curves.Scalar
capRSigma curves.Point
capRRho curves.Point
capRDeltaSigma curves.Point
capRDeltaRho curves.Point
capRE curves.Scalar
accumulator curves.Point
witnessValue curves.Scalar
xG1 curves.Point
yG1 curves.Point
zG1 curves.Point
}
// New initiates values of MembershipProofCommitting
func (mpc *MembershipProofCommitting) New(
witness *MembershipWitness,
acc *Accumulator,
pp *ProofParams,
pk *PublicKey,
) (*MembershipProofCommitting, error) {
// Randomly select σ, ρ
sigma := witness.y.Random(crand.Reader)
rho := witness.y.Random(crand.Reader)
// E_C = C + (σ + ρ)Z
t := sigma
t = t.Add(rho)
eC := pp.z
eC = eC.Mul(t)
eC = eC.Add(witness.c)
// T_σ = σX
tSigma := pp.x
tSigma = tSigma.Mul(sigma)
// T_ρ = ρY
tRho := pp.y
tRho = tRho.Mul(rho)
// δ_σ = yσ
deltaSigma := witness.y
deltaSigma = deltaSigma.Mul(sigma)
// δ_ρ = yρ
deltaRho := witness.y
deltaRho = deltaRho.Mul(rho)
// Randomly pick r_σ,r_ρ,r_δσ,r_δρ
rY := witness.y.Random(crand.Reader)
rSigma := witness.y.Random(crand.Reader)
rRho := witness.y.Random(crand.Reader)
rDeltaSigma := witness.y.Random(crand.Reader)
rDeltaRho := witness.y.Random(crand.Reader)
// R_σ = r_σ X
capRSigma := pp.x
capRSigma = capRSigma.Mul(rSigma)
// R_ρ = ρY
capRRho := pp.y
capRRho = capRRho.Mul(rRho)
// R_δσ = r_y T_σ - r_δσ X
negX := pp.x
negX = negX.Neg()
capRDeltaSigma := tSigma.Mul(rY)
capRDeltaSigma = capRDeltaSigma.Add(negX.Mul(rDeltaSigma))
// R_δρ = r_y T_ρ - r_δρ Y
negY := pp.y
negY = negY.Neg()
capRDeltaRho := tRho.Mul(rY)
capRDeltaRho = capRDeltaRho.Add(negY.Mul(rDeltaRho))
// P~
g2 := pk.value.Generator()
// -r_δσ - r_δρ
exp := rDeltaSigma
exp = exp.Add(rDeltaRho)
exp = exp.Neg()
// -r_σ - r_ρ
exp2 := rSigma
exp2 = exp2.Add(rRho)
exp2 = exp2.Neg()
// rY * eC
rYeC := eC.Mul(rY)
// (-r_δσ - r_δρ)*Z
expZ := pp.z.Mul(exp)
// (-r_σ - r_ρ)*Z
exp2Z := pp.z.Mul(exp2)
// Prepare
rYeCPrep, ok := rYeC.(curves.PairingPoint)
if !ok {
return nil, errors.New("incorrect type conversion")
}
g2Prep, ok := g2.(curves.PairingPoint)
if !ok {
return nil, errors.New("incorrect type conversion")
}
expZPrep, ok := expZ.(curves.PairingPoint)
if !ok {
return nil, errors.New("incorrect type conversion")
}
exp2ZPrep, ok := exp2Z.(curves.PairingPoint)
if !ok {
return nil, errors.New("incorrect type conversion")
}
pkPrep := pk.value
// Pairing
capRE := g2Prep.MultiPairing(rYeCPrep, g2Prep, expZPrep, g2Prep, exp2ZPrep, pkPrep)
return &MembershipProofCommitting{
eC,
tSigma,
tRho,
deltaSigma,
deltaRho,
rY,
rSigma,
rRho,
rDeltaSigma,
rDeltaRho,
sigma,
rho,
capRSigma,
capRRho,
capRDeltaSigma,
capRDeltaRho,
capRE,
acc.value,
witness.y,
pp.x,
pp.y,
pp.z,
}, nil
}
// GetChallengeBytes returns bytes that need to be hashed for generating challenge.
// V || Ec || T_sigma || T_rho || R_E || R_sigma || R_rho || R_delta_sigma || R_delta_rho
func (mpc MembershipProofCommitting) GetChallengeBytes() []byte {
res := mpc.accumulator.ToAffineCompressed()
res = append(res, mpc.eC.ToAffineCompressed()...)
res = append(res, mpc.tSigma.ToAffineCompressed()...)
res = append(res, mpc.tRho.ToAffineCompressed()...)
res = append(res, mpc.capRE.Bytes()...)
res = append(res, mpc.capRSigma.ToAffineCompressed()...)
res = append(res, mpc.capRRho.ToAffineCompressed()...)
res = append(res, mpc.capRDeltaSigma.ToAffineCompressed()...)
res = append(res, mpc.capRDeltaRho.ToAffineCompressed()...)
return res
}
// GenProof computes the s values for Fiat-Shamir and return the actual
// proof to be sent to the verifier given the challenge c.
func (mpc *MembershipProofCommitting) GenProof(c curves.Scalar) *MembershipProof {
// s_y = r_y + c*y
sY := schnorr(mpc.blindingFactor, mpc.witnessValue, c)
// s_σ = r_σ + c*σ
sSigma := schnorr(mpc.rSigma, mpc.sigma, c)
// s_ρ = r_ρ + c*ρ
sRho := schnorr(mpc.rRho, mpc.rho, c)
// s_δσ = rδσ + c*δ_σ
sDeltaSigma := schnorr(mpc.rDeltaSigma, mpc.deltaSigma, c)
// s_δρ = rδρ + c*δ_ρ
sDeltaRho := schnorr(mpc.rDeltaRho, mpc.deltaRho, c)
return &MembershipProof{
mpc.eC,
mpc.tSigma,
mpc.tRho,
sSigma,
sRho,
sDeltaSigma,
sDeltaRho,
sY,
}
}
func schnorr(r, v, challenge curves.Scalar) curves.Scalar {
res := v
res = res.Mul(challenge)
res = res.Add(r)
return res
}
type membershipProofMarshal struct {
EC []byte `bare:"e_c"`
TSigma []byte `bare:"t_sigma"`
TRho []byte `bare:"t_rho"`
SSigma []byte `bare:"s_sigma"`
SRho []byte `bare:"s_rho"`
SDeltaSigma []byte `bare:"s_delta_sigma"`
SDeltaRho []byte `bare:"s_delta_rho"`
SY []byte `bare:"s_y"`
Curve string `bare:"curve"`
}
// MembershipProof contains values in the proof to be verified
type MembershipProof struct {
eC curves.Point
tSigma curves.Point
tRho curves.Point
sSigma curves.Scalar
sRho curves.Scalar
sDeltaSigma curves.Scalar
sDeltaRho curves.Scalar
sY curves.Scalar
}
// Finalize computes values in the proof to be verified.
func (mp *MembershipProof) Finalize(
acc *Accumulator,
pp *ProofParams,
pk *PublicKey,
challenge curves.Scalar,
) (*MembershipProofFinal, error) {
// R_σ = s_δ X + c T_σ
negTSigma := mp.tSigma
negTSigma = negTSigma.Neg()
capRSigma := pp.x.Mul(mp.sSigma)
capRSigma = capRSigma.Add(negTSigma.Mul(challenge))
// R_ρ = s_ρ Y + c T_ρ
negTRho := mp.tRho
negTRho = negTRho.Neg()
capRRho := pp.y.Mul(mp.sRho)
capRRho = capRRho.Add(negTRho.Mul(challenge))
// R_δσ = s_y T_σ - s_δσ X
negX := pp.x
negX = negX.Neg()
capRDeltaSigma := mp.tSigma.Mul(mp.sY)
capRDeltaSigma = capRDeltaSigma.Add(negX.Mul(mp.sDeltaSigma))
// R_δρ = s_y T_ρ - s_δρ Y
negY := pp.y
negY = negY.Neg()
capRDeltaRho := mp.tRho.Mul(mp.sY)
capRDeltaRho = capRDeltaRho.Add(negY.Mul(mp.sDeltaRho))
// tildeP
g2 := pk.value.Generator()
// Compute capRE, the pairing
// E_c * s_y
eCsY := mp.eC.Mul(mp.sY)
// (-s_delta_sigma - s_delta_rho) * Z
exp := mp.sDeltaSigma
exp = exp.Add(mp.sDeltaRho)
exp = exp.Neg()
expZ := pp.z.Mul(exp)
// (-c) * V
exp = challenge.Neg()
expV := acc.value.Mul(exp)
// E_c * s_y + (-s_delta_sigma - s_delta_rho) * Z + (-c) * V
lhs := eCsY.Add(expZ).Add(expV)
// (-s_sigma - s_rho) * Z
exp = mp.sSigma
exp = exp.Add(mp.sRho)
exp = exp.Neg()
expZ2 := pp.z.Mul(exp)
// E_c * c
cEc := mp.eC.Mul(challenge)
// (-s_sigma - s_rho) * Z + E_c * c
rhs := cEc.Add(expZ2)
// Prepare
lhsPrep, ok := lhs.(curves.PairingPoint)
if !ok {
return nil, errors.New("incorrect type conversion")
}
g2Prep, ok := g2.(curves.PairingPoint)
if !ok {
return nil, errors.New("incorrect type conversion")
}
rhsPrep, ok := rhs.(curves.PairingPoint)
if !ok {
return nil, errors.New("incorrect type conversion")
}
pkPrep := pk.value
// capRE
capRE := g2Prep.MultiPairing(lhsPrep, g2Prep, rhsPrep, pkPrep)
return &MembershipProofFinal{
acc.value,
mp.eC,
mp.tSigma,
mp.tRho,
capRE,
capRSigma,
capRRho,
capRDeltaSigma,
capRDeltaRho,
}, nil
}
// MarshalBinary converts MembershipProof to bytes
func (mp MembershipProof) MarshalBinary() ([]byte, error) {
tv := &membershipProofMarshal{
EC: mp.eC.ToAffineCompressed(),
TSigma: mp.tSigma.ToAffineCompressed(),
TRho: mp.tRho.ToAffineCompressed(),
SSigma: mp.sSigma.Bytes(),
SRho: mp.sRho.Bytes(),
SDeltaSigma: mp.sDeltaSigma.Bytes(),
SDeltaRho: mp.sDeltaRho.Bytes(),
SY: mp.sY.Bytes(),
Curve: mp.eC.CurveName(),
}
return bare.Marshal(tv)
}
// UnmarshalBinary converts bytes to MembershipProof
func (mp *MembershipProof) UnmarshalBinary(data []byte) error {
if data == nil {
return fmt.Errorf("expected non-zero byte sequence")
}
tv := new(membershipProofMarshal)
err := bare.Unmarshal(data, tv)
if err != nil {
return err
}
curve := curves.GetCurveByName(tv.Curve)
if curve == nil {
return fmt.Errorf("invalid curve")
}
eC, err := curve.NewIdentityPoint().FromAffineCompressed(tv.EC)
if err != nil {
return err
}
tSigma, err := curve.NewIdentityPoint().FromAffineCompressed(tv.TSigma)
if err != nil {
return err
}
tRho, err := curve.NewIdentityPoint().FromAffineCompressed(tv.TRho)
if err != nil {
return err
}
sSigma, err := curve.NewScalar().SetBytes(tv.SSigma)
if err != nil {
return err
}
sRho, err := curve.NewScalar().SetBytes(tv.SRho)
if err != nil {
return err
}
sDeltaSigma, err := curve.NewScalar().SetBytes(tv.SDeltaSigma)
if err != nil {
return err
}
sDeltaRho, err := curve.NewScalar().SetBytes(tv.SDeltaRho)
if err != nil {
return err
}
sY, err := curve.NewScalar().SetBytes(tv.SY)
if err != nil {
return err
}
mp.eC = eC
mp.tSigma = tSigma
mp.tRho = tRho
mp.sSigma = sSigma
mp.sRho = sRho
mp.sDeltaSigma = sDeltaSigma
mp.sDeltaRho = sDeltaRho
mp.sY = sY
return nil
}
// MembershipProofFinal contains values that are input to Fiat-Shamir Heuristic
type MembershipProofFinal struct {
accumulator curves.Point
eC curves.Point
tSigma curves.Point
tRho curves.Point
capRE curves.Scalar
capRSigma curves.Point
capRRho curves.Point
capRDeltaSigma curves.Point
capRDeltaRho curves.Point
}
// GetChallenge computes Fiat-Shamir Heuristic taking input values of MembershipProofFinal
func (m MembershipProofFinal) GetChallenge(curve *curves.PairingCurve) curves.Scalar {
res := m.accumulator.ToAffineCompressed()
res = append(res, m.eC.ToAffineCompressed()...)
res = append(res, m.tSigma.ToAffineCompressed()...)
res = append(res, m.tRho.ToAffineCompressed()...)
res = append(res, m.capRE.Bytes()...)
res = append(res, m.capRSigma.ToAffineCompressed()...)
res = append(res, m.capRRho.ToAffineCompressed()...)
res = append(res, m.capRDeltaSigma.ToAffineCompressed()...)
res = append(res, m.capRDeltaRho.ToAffineCompressed()...)
challenge := curve.Scalar.Hash(res)
return challenge
}
+182
View File
@@ -0,0 +1,182 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/sonr-io/sonr/crypto/core/curves"
)
func TestProofParamsMarshal(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
pk, _ := sk.GetPublicKey(curve)
params, err := new(ProofParams).New(curve, pk, []byte("entropy"))
require.NoError(t, err)
require.NotNil(t, params.x)
require.NotNil(t, params.y)
require.NotNil(t, params.z)
bytes, err := params.MarshalBinary()
require.NoError(t, err)
require.NotNil(t, bytes)
params2 := &ProofParams{
curve.PointG1.Generator(),
curve.PointG1.Generator(),
curve.PointG1.Generator(),
}
err = params2.UnmarshalBinary(bytes)
require.NoError(t, err)
require.True(t, params.x.Equal(params2.x))
require.True(t, params.y.Equal(params2.y))
require.True(t, params.z.Equal(params2.z))
}
func TestMembershipProof(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
pk, _ := sk.GetPublicKey(curve)
element1 := curve.Scalar.Hash([]byte("3"))
element2 := curve.Scalar.Hash([]byte("4"))
element3 := curve.Scalar.Hash([]byte("5"))
element4 := curve.Scalar.Hash([]byte("6"))
element5 := curve.Scalar.Hash([]byte("7"))
element6 := curve.Scalar.Hash([]byte("8"))
element7 := curve.Scalar.Hash([]byte("9"))
elements := []Element{element1, element2, element3, element4, element5, element6, element7}
// Initiate a new accumulator
acc, err := new(Accumulator).WithElements(curve, sk, elements)
require.NoError(t, err)
require.NotNil(t, acc.value)
// Initiate a new membership witness for value elements[3]
wit, err := new(MembershipWitness).New(elements[3], acc, sk)
require.NoError(t, err)
require.Equal(t, wit.y, elements[3])
// Create proof parameters, which contains randomly sampled G1 points X, Y, Z, K
params, err := new(ProofParams).New(curve, pk, []byte("entropy"))
require.NoError(t, err)
require.NotNil(t, params.x)
require.NotNil(t, params.y)
require.NotNil(t, params.z)
mpc, err := new(MembershipProofCommitting).New(wit, acc, params, pk)
require.NoError(t, err)
testMPC(t, mpc)
challenge := curve.Scalar.Hash(mpc.GetChallengeBytes())
require.NotNil(t, challenge)
proof := mpc.GenProof(challenge)
require.NotNil(t, proof)
testProof(t, proof)
finalProof, err := proof.Finalize(acc, params, pk, challenge)
require.NoError(t, err)
require.NotNil(t, finalProof)
testFinalProof(t, finalProof)
challenge2 := finalProof.GetChallenge(curve)
require.Equal(t, challenge, challenge2)
// Check we can still have a valid proof even if accumulator and witness are updated
data1 := curve.Scalar.Hash([]byte("1"))
data2 := curve.Scalar.Hash([]byte("2"))
data3 := curve.Scalar.Hash([]byte("3"))
data4 := curve.Scalar.Hash([]byte("4"))
data5 := curve.Scalar.Hash([]byte("5"))
data := []Element{data1, data2, data3, data4, data5}
additions := data[0:2]
deletions := data[2:5]
_, coefficients, err := acc.Update(sk, additions, deletions)
require.NoError(t, err)
require.NotNil(t, coefficients)
_, err = wit.BatchUpdate(additions, deletions, coefficients)
require.NoError(t, err)
newParams, err := new(ProofParams).New(curve, pk, []byte("entropy"))
require.NoError(t, err)
require.NotNil(t, newParams.x)
require.NotNil(t, newParams.y)
require.NotNil(t, newParams.z)
newMPC, err := new(MembershipProofCommitting).New(wit, acc, newParams, pk)
require.NoError(t, err)
testMPC(t, newMPC)
challenge3 := curve.Scalar.Hash(newMPC.GetChallengeBytes())
require.NotNil(t, challenge3)
newProof := newMPC.GenProof(challenge3)
require.NotNil(t, newProof)
testProof(t, newProof)
newFinalProof, err := newProof.Finalize(acc, newParams, pk, challenge3)
require.NoError(t, err)
require.NotNil(t, newFinalProof)
testFinalProof(t, newFinalProof)
challenge4 := newFinalProof.GetChallenge(curve)
require.Equal(t, challenge3, challenge4)
}
func testMPC(t *testing.T, mpc *MembershipProofCommitting) {
require.NotNil(t, mpc.eC)
require.NotNil(t, mpc.tSigma)
require.NotNil(t, mpc.tRho)
require.NotNil(t, mpc.deltaSigma)
require.NotNil(t, mpc.deltaRho)
require.NotNil(t, mpc.blindingFactor)
require.NotNil(t, mpc.rSigma)
require.NotNil(t, mpc.rRho)
require.NotNil(t, mpc.rDeltaSigma)
require.NotNil(t, mpc.rDeltaRho)
require.NotNil(t, mpc.sigma)
require.NotNil(t, mpc.rho)
require.NotNil(t, mpc.capRSigma)
require.NotNil(t, mpc.capRRho)
require.NotNil(t, mpc.capRDeltaSigma)
require.NotNil(t, mpc.capRDeltaRho)
require.NotNil(t, mpc.capRE)
require.NotNil(t, mpc.accumulator)
require.NotNil(t, mpc.witnessValue)
require.NotNil(t, mpc.xG1)
require.NotNil(t, mpc.yG1)
require.NotNil(t, mpc.zG1)
}
func testProof(t *testing.T, proof *MembershipProof) {
require.NotNil(t, proof.eC)
require.NotNil(t, proof.tSigma)
require.NotNil(t, proof.tRho)
require.NotNil(t, proof.sSigma)
require.NotNil(t, proof.sRho)
require.NotNil(t, proof.sDeltaSigma)
require.NotNil(t, proof.sDeltaRho)
require.NotNil(t, proof.sY)
}
func testFinalProof(t *testing.T, finalProof *MembershipProofFinal) {
require.NotNil(t, finalProof.accumulator)
require.NotNil(t, finalProof.eC)
require.NotNil(t, finalProof.tSigma)
require.NotNil(t, finalProof.tRho)
require.NotNil(t, finalProof.capRE)
require.NotNil(t, finalProof.capRSigma)
require.NotNil(t, finalProof.capRRho)
require.NotNil(t, finalProof.capRDeltaSigma)
require.NotNil(t, finalProof.capRDeltaRho)
}
+392
View File
@@ -0,0 +1,392 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"errors"
"fmt"
"git.sr.ht/~sircmpwn/go-bare"
"github.com/sonr-io/sonr/crypto/core/curves"
)
// MembershipWitness contains the witness c and the value y respect to the accumulator state.
type MembershipWitness struct {
c curves.Point
y curves.Scalar
}
// New creates a new membership witness
func (mw *MembershipWitness) New(
y Element,
acc *Accumulator,
sk *SecretKey,
) (*MembershipWitness, error) {
if acc.value == nil || acc.value.IsIdentity() {
return nil, fmt.Errorf("value of accumulator should not be nil")
}
if sk.value == nil || sk.value.IsZero() {
return nil, fmt.Errorf("secret key should not be nil")
}
if y == nil || y.IsZero() {
return nil, fmt.Errorf("y should not be nil")
}
newAcc := &Accumulator{acc.value}
_, err := newAcc.Remove(sk, y)
if err != nil {
return nil, err
}
mw.c = newAcc.value
mw.y = y.Add(y.Zero())
return mw, nil
}
// Verify the MembershipWitness mw is a valid witness as per section 4 in
// <https://eprint.iacr.org/2020/777>
func (mw MembershipWitness) Verify(pk *PublicKey, acc *Accumulator) error {
if mw.c == nil || mw.y == nil || mw.c.IsIdentity() || mw.y.IsZero() {
return fmt.Errorf("c and y should not be nil")
}
if pk.value == nil || pk.value.IsIdentity() {
return fmt.Errorf("invalid public key")
}
if acc.value == nil || acc.value.IsIdentity() {
return fmt.Errorf("accumulator value should not be nil")
}
// Set -tildeP
g2, ok := pk.value.Generator().(curves.PairingPoint)
if !ok {
return errors.New("incorrect type conversion")
}
// y*tildeP + tildeQ, tildeP is a G2 generator.
p, ok := g2.Mul(mw.y).Add(pk.value).(curves.PairingPoint)
if !ok {
return errors.New("incorrect type conversion")
}
// Prepare
witness, ok := mw.c.(curves.PairingPoint)
if !ok {
return errors.New("incorrect type conversion")
}
v, ok := acc.value.Neg().(curves.PairingPoint)
if !ok {
return errors.New("incorrect type conversion")
}
// Check e(witness, y*tildeP + tildeQ) * e(-acc, tildeP) == Identity
result := p.MultiPairing(witness, p, v, g2)
if !result.IsOne() {
return fmt.Errorf("invalid result")
}
return nil
}
// ApplyDelta returns C' = dA(y)/dD(y)*C + 1/dD(y) * <Gamma_y, Omega>
// according to the witness update protocol described in section 4 of
// https://eprint.iacr.org/2020/777.pdf
func (mw *MembershipWitness) ApplyDelta(delta *Delta) (*MembershipWitness, error) {
if mw.c == nil || mw.y == nil || delta == nil {
return nil, fmt.Errorf("y, c or delta should not be nil")
}
// C' = dA(y)/dD(y)*C + 1/dD(y) * <Gamma_y, Omega>
mw.c = mw.c.Mul(delta.d).Add(delta.p)
return mw, nil
}
// BatchUpdate performs batch update as described in section 4
func (mw *MembershipWitness) BatchUpdate(
additions []Element,
deletions []Element,
coefficients []Coefficient,
) (*MembershipWitness, error) {
delta, err := evaluateDelta(mw.y, additions, deletions, coefficients)
if err != nil {
return nil, err
}
mw, err = mw.ApplyDelta(delta)
if err != nil {
return nil, fmt.Errorf("applyDelta fails")
}
return mw, nil
}
// MultiBatchUpdate performs multi-batch update using epoch as described in section 4.2
func (mw *MembershipWitness) MultiBatchUpdate(
A [][]Element,
D [][]Element,
C [][]Coefficient,
) (*MembershipWitness, error) {
delta, err := evaluateDeltas(mw.y, A, D, C)
if err != nil {
return nil, fmt.Errorf("evaluateDeltas fails")
}
mw, err = mw.ApplyDelta(delta)
if err != nil {
return nil, err
}
return mw, nil
}
// MarshalBinary converts a membership witness to bytes
func (mw MembershipWitness) MarshalBinary() ([]byte, error) {
if mw.c == nil || mw.y == nil {
return nil, fmt.Errorf("c and y value should not be nil")
}
result := append(mw.c.ToAffineCompressed(), mw.y.Bytes()...)
tv := &structMarshal{
Value: result,
Curve: mw.c.CurveName(),
}
return bare.Marshal(tv)
}
// UnmarshalBinary converts bytes into MembershipWitness
func (mw *MembershipWitness) UnmarshalBinary(data []byte) error {
if data == nil {
return fmt.Errorf("input data should not be nil")
}
tv := new(structMarshal)
err := bare.Unmarshal(data, tv)
if err != nil {
return err
}
curve := curves.GetCurveByName(tv.Curve)
if curve == nil {
return fmt.Errorf("invalid curve")
}
ptLength := len(curve.Point.ToAffineCompressed())
scLength := len(curve.Scalar.Bytes())
expectedLength := ptLength + scLength
if len(tv.Value) != expectedLength {
return fmt.Errorf("invalid byte sequence")
}
cValue, err := curve.Point.FromAffineCompressed(tv.Value[:ptLength])
if err != nil {
return err
}
yValue, err := curve.Scalar.SetBytes(tv.Value[ptLength:])
if err != nil {
return err
}
mw.c = cValue
mw.y = yValue
return nil
}
// Delta contains values d and p, where d should be the division dA(y)/dD(y) on some value y
// p should be equal to 1/dD * <Gamma_y, Omega>
type Delta struct {
d curves.Scalar
p curves.Point
}
// MarshalBinary converts Delta into bytes
func (d *Delta) MarshalBinary() ([]byte, error) {
if d.d == nil || d.p == nil {
return nil, fmt.Errorf("d and p should not be nil")
}
var result []byte
result = append(result, d.p.ToAffineCompressed()...)
result = append(result, d.d.Bytes()...)
tv := &structMarshal{
Value: result,
Curve: d.p.CurveName(),
}
return bare.Marshal(tv)
}
// UnmarshalBinary converts data into Delta
func (d *Delta) UnmarshalBinary(data []byte) error {
if data == nil {
return fmt.Errorf("expected non-zero byte sequence")
}
tv := new(structMarshal)
err := bare.Unmarshal(data, tv)
if err != nil {
return err
}
curve := curves.GetCurveByName(tv.Curve)
if curve == nil {
return fmt.Errorf("invalid curve")
}
ptLength := len(curve.Point.ToAffineCompressed())
scLength := len(curve.Scalar.Bytes())
expectedLength := ptLength + scLength
if len(tv.Value) != expectedLength {
return fmt.Errorf("invalid byte sequence")
}
pValue, err := curve.NewIdentityPoint().FromAffineCompressed(tv.Value[:ptLength])
if err != nil {
return err
}
dValue, err := curve.NewScalar().SetBytes(tv.Value[ptLength:])
if err != nil {
return err
}
d.d = dValue
d.p = pValue
return nil
}
// evaluateDeltas compute values used for membership witness batch update with epoch
// as described in section 4.2, page 11 of https://eprint.iacr.org/2020/777.pdf
func evaluateDeltas(y Element, A [][]Element, D [][]Element, C [][]Coefficient) (*Delta, error) {
if len(A) != len(D) || len(A) != len(C) {
return nil, fmt.Errorf("a, d, c should have same length")
}
one := y.One()
size := len(A)
// dA(x) = ∏ 1..n (yA_i - x)
aa := make([]curves.Scalar, 0)
// dD(x) = ∏ 1..m (yD_i - x)
dd := make([]curves.Scalar, 0)
a := one
d := one
// dA_{a->b}(y) = ∏ a..b dAs(y)
// dD_{a->b}(y) = ∏ a..b dDs(y)
for i := range size {
adds := A[i]
dels := D[i]
// ta = dAs(y)
ta, err := dad(adds, y)
if err != nil {
return nil, fmt.Errorf("dad on additions fails")
}
// td = dDs(y)
td, err := dad(dels, y)
if err != nil {
return nil, fmt.Errorf("dad on deletions fails")
}
// ∏ a..b dAs(y)
a = a.Mul(ta)
// ∏ a..b dDs(y)
d = d.Mul(td)
aa = append(aa, ta)
dd = append(dd, td)
}
// If this fails, then this value was removed.
d, err := d.Invert()
if err != nil {
return nil, fmt.Errorf("no inverse exists")
}
// <Gamma_y, Omega>
p := make(polynomialPoint, 0, size)
// Ωi->j+1 = ∑ 1..t (dAt * dDt-1) · Ω
for i := 0; i < size; i++ {
// t = i+1
// ∏^(t-1)_(h=i+1)
ddh := one
// dDi→t1 (y)
for h := 0; h < i; h++ {
ddh = ddh.Mul(dd[h])
}
// ∏^(j+1)_(k=t+1)
dak := one
// dAt->j(y)
for k := i + 1; k < size; k++ {
dak = dak.Mul(aa[k])
}
// dDi->t-1(y) * dAt->j(y)
dak = dak.Mul(ddh)
pp := make(polynomialPoint, len(C[i]))
for j := 0; j < len(pp); j++ {
pp[j] = C[i][j]
}
// dDi->t-1(y) * dAt->j(y) · Ω
pp, err := pp.Mul(dak)
if err != nil {
return nil, fmt.Errorf("pp.Mul fails")
}
p, err = p.Add(pp)
if err != nil {
return nil, fmt.Errorf("pp.Add fails")
}
}
// dAi->j(y)/dDi->j(y)
a = a.Mul(d)
// Ωi->j(y)
v, err := p.evaluate(y)
if err != nil {
return nil, fmt.Errorf("p.evaluate fails")
}
// (1/dDi->j(y)) * Ωi->j(y)
v = v.Mul(d)
// return
return &Delta{d: a, p: v}, nil
}
// evaluateDelta computes values used for membership witness batch update
// as described in section 4.1 of https://eprint.iacr.org/2020/777.pdf
func evaluateDelta(
y Element,
additions []Element,
deletions []Element,
coefficients []Coefficient,
) (*Delta, error) {
// dD(y) = ∏ 1..m (yD_i - y), d = 1/dD(y)
var err error
d, err := dad(deletions, y)
if err != nil {
return nil, fmt.Errorf("dad fails on deletions")
}
d, err = d.Invert()
if err != nil {
return nil, fmt.Errorf("no inverse exists")
}
// dA(y) = ∏ 1..n (yA_i - y)
a, err := dad(additions, y)
if err != nil {
return nil, fmt.Errorf("dad fails on additions")
}
// dA(y)/dD(y)
a = a.Mul(d)
// Create a PolynomialG1 from coefficients
p := make(polynomialPoint, len(coefficients))
for i := range coefficients {
p[i] = coefficients[i]
}
// <Gamma_y, Omega>
v, err := p.evaluate(y)
if err != nil {
return nil, fmt.Errorf("p.evaluate fails")
}
// 1/dD * <Gamma_y, Omega>
v = v.Mul(d)
return &Delta{d: a, p: v}, nil
}
+229
View File
@@ -0,0 +1,229 @@
//
// Copyright Coinbase, Inc. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//
package accumulator
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/sonr-io/sonr/crypto/core/curves"
)
func Test_Membership_Witness_New(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
var seed [32]byte
key, _ := new(SecretKey).New(curve, seed[:])
acc, _ := new(Accumulator).New(curve)
e := curve.Scalar.New(2)
mw, err := new(MembershipWitness).New(e, acc, key)
require.NoError(t, err)
require.NotNil(t, mw.c)
require.NotNil(t, mw.y)
}
func Test_Membership_Witness_Marshal(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
mw := &MembershipWitness{
curve.PointG1.Generator().Mul(curve.Scalar.New(10)),
curve.Scalar.New(15),
}
data, err := mw.MarshalBinary()
require.NoError(t, err)
require.NotNil(t, data)
newMW := &MembershipWitness{}
err = newMW.UnmarshalBinary(data)
require.NoError(t, err)
require.True(t, mw.c.Equal(newMW.c))
require.Equal(t, 0, mw.y.Cmp(newMW.y))
}
func Test_Membership(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
pk, _ := sk.GetPublicKey(curve)
element1 := curve.Scalar.Hash([]byte("3"))
element2 := curve.Scalar.Hash([]byte("4"))
element3 := curve.Scalar.Hash([]byte("5"))
element4 := curve.Scalar.Hash([]byte("6"))
element5 := curve.Scalar.Hash([]byte("7"))
element6 := curve.Scalar.Hash([]byte("8"))
element7 := curve.Scalar.Hash([]byte("9"))
elements := []Element{element1, element2, element3, element4, element5, element6, element7}
// nm_witness_max works as well if set to value larger than 0 for this test.x
acc, err := new(Accumulator).WithElements(curve, sk, elements)
require.NoError(t, err)
require.NotNil(t, acc.value)
require.False(t, acc.value.IsIdentity())
require.True(t, acc.value.IsOnCurve())
require.NotEqual(t, acc.value, curve.NewG1GeneratorPoint())
wit, err := new(MembershipWitness).New(elements[3], acc, sk)
require.NoError(t, err)
require.Equal(t, wit.y, elements[3])
err = wit.Verify(pk, acc)
require.NoError(t, err)
// Test wrong cases, forge a wrong witness
wrongWit := MembershipWitness{
curve.PointG1.Identity(),
curve.Scalar.One(),
}
err = wrongWit.Verify(pk, acc)
require.Error(t, err)
// Test wrong cases, forge a wrong accumulator
wrongAcc := &Accumulator{
curve.PointG1.Generator(),
}
err = wit.Verify(pk, wrongAcc)
require.Error(t, err)
}
func Test_Membership_Batch_Update(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
pk, _ := sk.GetPublicKey(curve)
element1 := curve.Scalar.Hash([]byte("3"))
element2 := curve.Scalar.Hash([]byte("4"))
element3 := curve.Scalar.Hash([]byte("5"))
element4 := curve.Scalar.Hash([]byte("6"))
element5 := curve.Scalar.Hash([]byte("7"))
element6 := curve.Scalar.Hash([]byte("8"))
element7 := curve.Scalar.Hash([]byte("9"))
elements := []Element{element1, element2, element3, element4, element5, element6, element7}
// nm_witness_max works as well if set to value larger than 0 for this test.
acc, err := new(Accumulator).WithElements(curve, sk, elements)
require.NoError(t, err)
require.NotNil(t, acc.value)
wit, err := new(MembershipWitness).New(elements[3], acc, sk)
require.NoError(t, err)
require.Equal(t, wit.y, elements[3])
err = wit.Verify(pk, acc)
require.Nil(t, err)
data1 := curve.Scalar.Hash([]byte("1"))
data2 := curve.Scalar.Hash([]byte("2"))
data3 := curve.Scalar.Hash([]byte("3"))
data4 := curve.Scalar.Hash([]byte("4"))
data5 := curve.Scalar.Hash([]byte("5"))
data := []Element{data1, data2, data3, data4, data5}
additions := data[0:2]
deletions := data[2:5]
_, coefficients, err := acc.Update(sk, additions, deletions)
require.NoError(t, err)
require.NotNil(t, coefficients)
_, err = wit.BatchUpdate(additions, deletions, coefficients)
require.NoError(t, err)
err = wit.Verify(pk, acc)
require.Nil(t, err)
}
func Test_Membership_Multi_Batch_Update(t *testing.T) {
curve := curves.BLS12381(&curves.PointBls12381G1{})
sk, _ := new(SecretKey).New(curve, []byte("1234567890"))
pk, _ := sk.GetPublicKey(curve)
element1 := curve.Scalar.Hash([]byte("3"))
element2 := curve.Scalar.Hash([]byte("4"))
element3 := curve.Scalar.Hash([]byte("5"))
element4 := curve.Scalar.Hash([]byte("6"))
element5 := curve.Scalar.Hash([]byte("7"))
element6 := curve.Scalar.Hash([]byte("8"))
element7 := curve.Scalar.Hash([]byte("9"))
element8 := curve.Scalar.Hash([]byte("10"))
element9 := curve.Scalar.Hash([]byte("11"))
element10 := curve.Scalar.Hash([]byte("12"))
element11 := curve.Scalar.Hash([]byte("13"))
element12 := curve.Scalar.Hash([]byte("14"))
element13 := curve.Scalar.Hash([]byte("15"))
element14 := curve.Scalar.Hash([]byte("16"))
element15 := curve.Scalar.Hash([]byte("17"))
element16 := curve.Scalar.Hash([]byte("18"))
element17 := curve.Scalar.Hash([]byte("19"))
element18 := curve.Scalar.Hash([]byte("20"))
elements := []Element{
element1,
element2,
element3,
element4,
element5,
element6,
element7,
element8,
element9,
element10,
element11,
element12,
element13,
element14,
element15,
element16,
element17,
element18,
}
acc, err := new(Accumulator).WithElements(curve, sk, elements)
require.NoError(t, err)
require.NotNil(t, acc.value)
wit, err := new(MembershipWitness).New(elements[3], acc, sk)
require.NoError(t, err)
err = wit.Verify(pk, acc)
require.Nil(t, err)
data1 := curve.Scalar.Hash([]byte("1"))
data2 := curve.Scalar.Hash([]byte("2"))
data3 := curve.Scalar.Hash([]byte("3"))
data4 := curve.Scalar.Hash([]byte("4"))
data5 := curve.Scalar.Hash([]byte("5"))
data := []Element{data1, data2, data3, data4, data5}
adds1 := data[0:2]
dels1 := data[2:5]
_, coeffs1, err := acc.Update(sk, adds1, dels1)
require.NoError(t, err)
require.NotNil(t, coeffs1)
dels2 := elements[8:10]
_, coeffs2, err := acc.Update(sk, []Element{}, dels2)
require.NoError(t, err)
require.NotNil(t, coeffs2)
dels3 := elements[11:14]
_, coeffs3, err := acc.Update(sk, []Element{}, dels3)
require.NoError(t, err)
require.NotNil(t, coeffs3)
a := make([][]Element, 3)
a[0] = adds1
a[1] = []Element{}
a[2] = []Element{}
d := make([][]Element, 3)
d[0] = dels1
d[1] = dels2
d[2] = dels3
c := make([][]Coefficient, 3)
c[0] = coeffs1
c[1] = coeffs2
c[2] = coeffs3
_, err = wit.MultiBatchUpdate(a, d, c)
require.NoError(t, err)
err = wit.Verify(pk, acc)
require.Nil(t, err)
}