mirror of
https://github.com/sonr-io/crypto.git
synced 2026-08-02 15:31:38 +00:00
No commit suggestions generated
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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→t−1 (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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user