github.com/dusk-network/dusk-crypto@v0.1.3/ringsig/blsag/blsag.go (about)

     1  package blsag
     2  
     3  import (
     4  	"bytes"
     5  	"math/rand"
     6  	"time"
     7  
     8  	ristretto "github.com/bwesterb/go-ristretto"
     9  )
    10  
    11  // RingSignature is the collection of signatures
    12  type RingSignature struct {
    13  	I       ristretto.Point    // key image
    14  	C       ristretto.Scalar   // C val
    15  	S       []ristretto.Scalar // S vals
    16  	PubKeys []ristretto.Point  // PubKeys including owner
    17  }
    18  
    19  // Sign will create the MLSAG components that can be used to verify the owner
    20  // Returns keyimage, a c val,
    21  func Sign(m []byte, mixin []ristretto.Point, sK ristretto.Scalar) RingSignature {
    22  
    23  	// pubKey pK such that pK = sK * G
    24  	var pK ristretto.Point
    25  	pK.ScalarMultBase(&sK)
    26  
    27  	// secret j index
    28  	rand.Seed(time.Now().UnixNano())
    29  	j := rand.Intn(len(mixin) + 1)
    30  
    31  	// Hp(pK)
    32  	var hPK ristretto.Point
    33  	hPK.Derive(pK.Bytes())
    34  
    35  	// I = xHp(pK)
    36  	var I ristretto.Point
    37  	I.ScalarMult(&hPK, &sK)
    38  
    39  	// alpha E Zq , where q is G
    40  	var alpha ristretto.Scalar
    41  	alpha.Rand()
    42  
    43  	// generate s_i where i =/= j and s_i E Zq
    44  	sVals := make([]ristretto.Scalar, len(mixin)+1)
    45  	for i := 1; i < len(sVals); i++ {
    46  		var s ristretto.Scalar
    47  		s.Rand()
    48  		sVals[i] = s
    49  	}
    50  
    51  	cVals := make([]ristretto.Scalar, len(mixin)+1)
    52  
    53  	// Lj = alpha * G
    54  	var Lj ristretto.Point
    55  	Lj.ScalarMultBase(&alpha)
    56  
    57  	// Rj = alpha * Hp(Pj)
    58  	var Rj ristretto.Point
    59  	Rj.ScalarMult(&hPK, &alpha)
    60  
    61  	// c_j+1 = Hs(m, Lj, Rj)
    62  	var cPlus1 ristretto.Scalar
    63  	buf := new(bytes.Buffer)
    64  	appendToBuf(buf, m, Lj.Bytes(), Rj.Bytes())
    65  	cPlus1.Derive(buf.Bytes())
    66  
    67  	jPlus1 := (j + 1) % len(cVals)
    68  	cVals[jPlus1] = cPlus1
    69  
    70  	pubKeys := make([]ristretto.Point, len(mixin)+1)
    71  	pubKeys[j] = pK // add signer
    72  
    73  	for i := j + 1; ; i++ {
    74  
    75  		l := i % (len(pubKeys))
    76  		if l == j {
    77  			break
    78  		}
    79  
    80  		k := (i + 1) % (len(pubKeys))
    81  
    82  		c, _, _ := computeCLR(m, I, pubKeys[l], sVals[l], cPlus1)
    83  
    84  		cVals[k] = c
    85  		cPlus1 = c
    86  	}
    87  
    88  	// calculate s_j = alpha - cPlus1 * privKey
    89  	var sj ristretto.Scalar
    90  	sj.Mul(&cPlus1, &sK).Neg(&sj).Add(&sj, &alpha)
    91  	sVals[j] = sj
    92  
    93  	ringsig := RingSignature{
    94  		I:       I,
    95  		C:       cVals[0],
    96  		S:       sVals,
    97  		PubKeys: pubKeys,
    98  	}
    99  	return ringsig
   100  }
   101  
   102  // Verify takes a message and a ringsig
   103  // returns true if the message was signed by a member of the ring
   104  func Verify(m []byte, ringsig RingSignature) bool {
   105  
   106  	// Two conditions are that:
   107  	// c_n+1 = c1 in 1 i mod n
   108  	// For all i, c_i+1 = H(m, L_i, R_i)
   109  
   110  	numPubKeys := len(ringsig.PubKeys)
   111  
   112  	currC := ringsig.C // this is first c value c[0]
   113  
   114  	Ls := make([]ristretto.Point, numPubKeys)
   115  	Rs := make([]ristretto.Point, numPubKeys)
   116  	Cs := make([]ristretto.Scalar, numPubKeys)
   117  
   118  	for i := 0; i < numPubKeys; i++ {
   119  
   120  		// First calculate Cs, Ls, Rs
   121  
   122  		cPlus1, L, R := computeCLR(m, ringsig.I, ringsig.PubKeys[i], ringsig.S[i], currC)
   123  
   124  		k := (i + 1) % numPubKeys
   125  
   126  		Cs[k] = cPlus1
   127  
   128  		Ls[i] = L
   129  		Rs[i] = R
   130  
   131  		currC = cPlus1
   132  	}
   133  
   134  	// check that c_i+1 = h(m || L_i || R_i)
   135  
   136  	if len(Ls) != len(Rs) && len(Rs) != len(Cs) {
   137  		return false
   138  	}
   139  
   140  	for i := range Cs {
   141  
   142  		buf := new(bytes.Buffer)
   143  		appendToBuf(buf, m, Ls[i].Bytes(), Rs[i].Bytes())
   144  
   145  		var cPlus1 ristretto.Scalar
   146  		cPlus1.Derive(buf.Bytes())
   147  
   148  		k := (i + 1) % len(Cs)
   149  
   150  		if !Cs[k].Equals(&cPlus1) {
   151  			return false
   152  		}
   153  
   154  	}
   155  
   156  	// c_n+1 = c[0]
   157  	if Cs[0] != ringsig.C {
   158  		return false
   159  	}
   160  
   161  	return true
   162  }
   163  
   164  // returns C, L, R
   165  func computeCLR(message []byte, I ristretto.Point, pubKey ristretto.Point, s ristretto.Scalar, c ristretto.Scalar) (ristretto.Scalar, ristretto.Point, ristretto.Point) {
   166  	var L1, L2, L, R1, R2, R, tmpPubKey, HTmpPubKey ristretto.Point
   167  
   168  	var cPlus1 ristretto.Scalar
   169  
   170  	tmpPubKey = pubKey
   171  
   172  	HTmpPubKey.Derive(tmpPubKey.Bytes())
   173  
   174  	//  L_j = s_j*G + c_j*P_j
   175  	L1.ScalarMultBase(&s)
   176  	L2.ScalarMult(&tmpPubKey, &c)
   177  	L.Add(&L1, &L2)
   178  
   179  	// R_j = s_j * Hp(P_j) + c_j * I
   180  	R1.ScalarMult(&HTmpPubKey, &s)
   181  	R2.ScalarMult(&I, &c)
   182  	R.Add(&R1, &R2)
   183  
   184  	buf := new(bytes.Buffer)
   185  	appendToBuf(buf, message, L.Bytes(), R.Bytes())
   186  	cPlus1.Derive(buf.Bytes())
   187  
   188  	return cPlus1, L, R
   189  }
   190  
   191  func appendToBuf(buf *bytes.Buffer, data ...[]byte) *bytes.Buffer {
   192  	for _, b := range data {
   193  		buf.Write(b)
   194  	}
   195  	return buf
   196  }