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 }