├── .gitignore ├── DEVELOPERS.md ├── README.md ├── audit.go ├── audit_test.go ├── bank.go ├── bank_test.go ├── clients.go ├── cmd ├── apl-auditor │ └── auditor.go ├── apl-bank │ └── bank.go ├── apl-ledger │ └── ledger.go ├── keygen │ └── keygen.go └── setup │ ├── .gitignore │ ├── apl_env.go │ ├── keys │ ├── b0_pk │ ├── b0_sk │ ├── b10_pk │ ├── b10_sk │ ├── b11_pk │ ├── b11_sk │ ├── b12_pk │ ├── b12_sk │ ├── b13_pk │ ├── b13_sk │ ├── b14_pk │ ├── b14_sk │ ├── b15_pk │ ├── b15_sk │ ├── b16_pk │ ├── b16_sk │ ├── b17_pk │ ├── b17_sk │ ├── b18_pk │ ├── b18_sk │ ├── b19_pk │ ├── b19_sk │ ├── b1_pk │ ├── b1_sk │ ├── b20_pk │ ├── b20_sk │ ├── b21_pk │ ├── b21_sk │ ├── b22_pk │ ├── b22_sk │ ├── b23_pk │ ├── b23_sk │ ├── b24_pk │ ├── b24_sk │ ├── b25_pk │ ├── b25_sk │ ├── b26_pk │ ├── b26_sk │ ├── b27_pk │ ├── b27_sk │ ├── b28_pk │ ├── b28_sk │ ├── b29_pk │ ├── b29_sk │ ├── b2_pk │ ├── b2_sk │ ├── b30_pk │ ├── b30_sk │ ├── b31_pk │ ├── b31_sk │ ├── b32_pk │ ├── b32_sk │ ├── b33_pk │ ├── b33_sk │ ├── b34_pk │ ├── b34_sk │ ├── b35_pk │ ├── b35_sk │ ├── b36_pk │ ├── b36_sk │ ├── b37_pk │ ├── b37_sk │ ├── b38_pk │ ├── b38_sk │ ├── b39_pk │ ├── b39_sk │ ├── b3_pk │ ├── b3_sk │ ├── b40_pk │ ├── b40_sk │ ├── b41_pk │ ├── b41_sk │ ├── b42_pk │ ├── b42_sk │ ├── b43_pk │ ├── b43_sk │ ├── b44_pk │ ├── b44_sk │ ├── b45_pk │ ├── b45_sk │ ├── b46_pk │ ├── b46_sk │ ├── b47_pk │ ├── b47_sk │ ├── b48_pk │ ├── b48_sk │ ├── b49_pk │ ├── b49_sk │ ├── b4_pk │ ├── b4_sk │ ├── b5_pk │ ├── b5_sk │ ├── b6_pk │ ├── b6_sk │ ├── b7_pk │ ├── b7_sk │ ├── b8_pk │ ├── b8_sk │ ├── b9_pk │ ├── b9_sk │ ├── is_pk │ └── is_sk │ └── main.go ├── debug.go ├── ledger.go ├── ledger_test.go ├── pki.go ├── testutil.go ├── transaction.go ├── zkcurve.go └── zkledger.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | zkledger.test 3 | cmd/apl-bank/apl-bank 4 | cmd/apl-bank/keys 5 | cmd/apl-ledger/apl-ledger 6 | cmd/apl-auditor/apl-auditor 7 | cmd/apl-auditor/keys 8 | cmd/keygen/keygen 9 | cmd/keygen/keys 10 | *.byte 11 | *.exe 12 | *.out 13 | *.prof -------------------------------------------------------------------------------- /DEVELOPERS.md: -------------------------------------------------------------------------------- 1 | # zkLedger File Structure 2 | 3 | ### Top Level 4 | 5 | All the zkLedger source code is contained in the top level directory. This includes auditor, bank, and ledger functionality. 6 | 7 | - **audit.go** 8 | - **bank.go** 9 | - **clients.go** 10 | - **debug.go** 11 | - **ledger.go** 12 | - **pki.go** 13 | - **system_test.go** 14 | - **testutil.go** 15 | - **transaction.go** 16 | 17 | ### cmd/ 18 | 19 | This directory contains the control infrastructure to actually run a zkLedger instance. 20 | 21 | - **apl-auditor/** 22 | - **apl-bank/** 23 | - **apl-ledger/** 24 | - **keygen/** 25 | - **setup/** 26 | 27 | To run experiments, `setup/` contains a testing harness for local and remote tests. 28 | 29 | - `main.go`: contains preset tests (e.g. r50TX_herf where every bank 30 | you pass in performs 50 transactions and at the end the Herfindahl 31 | index is calculated between them) but also has the flexibility to 32 | insert others. It also can execute tests when servers are on 33 | different machines. 34 | - `apl_env.go`: contains methods to create the environment for zkLedger to execute, either locally or remotely. 35 | - `keys/`: **DO NOT USE THESE IN PRODUCTION ENVIRONMENTS** contains a collection of 50 bank public/private key pairs for testing. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # zkLedger 2 | 3 | zkLedger is a design for a ledger which has private transactions, but supports provably-correct queries over the ledger. 4 | 5 | Maybe you'd like to run the tests: 6 | 7 | ``` 8 | cd $GOPATH/src/github.com/mit-dci/zkledger 9 | go test 10 | ``` 11 | 12 | Or, run a local experiment with a few banks, a single-server ledger, and an auditor: 13 | 14 | 15 | ``` 16 | cd cmd/setup 17 | go build 18 | ./setup -t simple1 19 | ``` 20 | 21 | (You can add `-debug` to get a lot of timing information and other debug output) -------------------------------------------------------------------------------- /audit.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math/big" 7 | "net" 8 | "net/rpc" 9 | "sync" 10 | 11 | "github.com/mit-dci/zksigma" 12 | ) 13 | 14 | type Auditor struct { 15 | num int 16 | local_ledger *LocalLedger 17 | receivedTxns chan *EncryptedTransaction 18 | mu *sync.Mutex 19 | lastSeen int 20 | Done chan bool 21 | banks []BankClient 22 | pki *PKI 23 | CommsCache []zksigma.ECPoint 24 | RTokenCache []zksigma.ECPoint 25 | Setup chan struct{} 26 | } 27 | 28 | func MakeAuditor(num int, pki *PKI) *Auditor { 29 | a := &Auditor{ 30 | num: num, 31 | local_ledger: MakeLocalLedger(), 32 | receivedTxns: make(chan *EncryptedTransaction, TXN_BUFFER), 33 | mu: new(sync.Mutex), 34 | lastSeen: -1, 35 | Done: make(chan bool), 36 | pki: pki, 37 | Setup: make(chan struct{}), 38 | } 39 | a.CommsCache = make([]zksigma.ECPoint, a.num) 40 | a.RTokenCache = make([]zksigma.ECPoint, a.num) 41 | for i := 0; i < a.num; i++ { 42 | a.CommsCache[i] = zksigma.Zero 43 | a.RTokenCache[i] = zksigma.Zero 44 | } 45 | go a.start() 46 | return a 47 | } 48 | 49 | func (a *Auditor) Go(c APLClientConfig, _ *struct{}) error { 50 | go a.register(c.Hostname, c.BasePort, c.BankHostnames) 51 | a.listen(c.Hostname, c.BasePort) 52 | return nil 53 | } 54 | 55 | func (a *Auditor) listen(hostname string, basePort int) { 56 | listener, err := net.Listen("tcp", fmt.Sprintf(":%d", basePort+a.num+2)) 57 | if err != nil { 58 | log.Fatalf("[A] Could not listen %v\n", err) 59 | } 60 | err = rpc.Register(a) 61 | if err != nil { 62 | panic(err) 63 | } 64 | for { 65 | conn, err := listener.Accept() 66 | if err != nil { 67 | fmt.Println(err) 68 | continue 69 | } 70 | go rpc.ServeConn(conn) 71 | } 72 | } 73 | 74 | func (a *Auditor) register(hostname string, baseport int, bankHostnames []string) { 75 | var wg sync.WaitGroup 76 | a.banks = make([]BankClient, a.num) 77 | for i := 0; i < a.num; i++ { 78 | wg.Add(1) 79 | go func(i int) { 80 | x := MakeRemoteBankClient() 81 | x.connect(bankHostnames[i], baseport+i+1) 82 | a.banks[i] = x 83 | wg.Done() 84 | }(i) 85 | } 86 | wg.Wait() 87 | Dprintf("[A] Registered with banks\n") 88 | close(a.Setup) 89 | } 90 | 91 | func (a *Auditor) start() { 92 | <-a.Setup 93 | Dprintf("[A] Starting audit loop...\n") 94 | var pks []zksigma.ECPoint 95 | for { 96 | select { 97 | case etx := <-a.receivedTxns: 98 | Dprintf("[A][%v] Received txn...\n", etx.Index) 99 | // Verify 100 | if pks == nil { 101 | pks = make([]zksigma.ECPoint, a.num+1) // all the banks and the issuer 102 | for i := 0; i < a.num+1; i++ { 103 | pks[i] = a.pki.Get(i) 104 | } 105 | } 106 | if *emptyTxn { 107 | continue 108 | } 109 | a.mu.Lock() 110 | if !etx.Verify(pks, a.CommsCache, a.RTokenCache, "A") { 111 | log.Fatalf("[A][%v] Bad transaction!\n", etx.Index) 112 | } 113 | Dprintf("[A][%v] Verified txn...\n", etx.Index) 114 | lastSeen := a.lastSeen 115 | a.mu.Unlock() 116 | if etx.Index < lastSeen { 117 | log.Fatalf("[A] lastSeen %v out of whack with received transactions %v\n", lastSeen, etx.Index) 118 | } else if etx.Index == lastSeen { 119 | log.Fatalf("[A] lastSeen %v out of whack with received transactions %v\n", lastSeen, etx.Index) 120 | } else if etx.Index == lastSeen+1 { 121 | a.mu.Lock() 122 | a.lastSeen = a.lastSeen + 1 123 | etx.reduce() 124 | a.local_ledger.add(etx) 125 | if etx.Type == Transfer { 126 | for i := 0; i < len(etx.Entries); i++ { 127 | //Dprintf("[A] Adding RToken %v...\n", etx.Entries[i].RToken) 128 | a.RTokenCache[i] = ZKLedgerCurve.Add(a.RTokenCache[i], etx.Entries[i].RToken) 129 | a.CommsCache[i] = ZKLedgerCurve.Add(a.CommsCache[i], etx.Entries[i].Comm) 130 | } 131 | } else if etx.Type == Issuance || etx.Type == Withdrawal { 132 | // Only one bank for now 133 | en := &etx.Entries[etx.Sender] 134 | gval := ZKLedgerCurve.Mult(ZKLedgerCurve.G, en.V) 135 | a.CommsCache[etx.Sender] = ZKLedgerCurve.Add(a.CommsCache[etx.Sender], gval) 136 | } 137 | Dprintf("[A][%v] Processed txn\n", etx.Index) 138 | a.mu.Unlock() 139 | } else { 140 | Dprintf("[A][%v] Received txn out of order, expected %v\n", etx.Index, a.lastSeen) 141 | a.receivedTxns <- etx 142 | } 143 | case <-a.Done: 144 | Dprintf("[A] Shutting down audit loop...\n") 145 | close(a.receivedTxns) 146 | return 147 | } 148 | } 149 | } 150 | 151 | func (a *Auditor) Stop(_ *struct{}, _ *struct{}) error { 152 | a.Done <- true 153 | return nil 154 | } 155 | 156 | func (a *Auditor) Notify(etx *EncryptedTransaction, _ *struct{}) error { 157 | Dprintf("[A][%v] Notified of txn\n", etx.Index) 158 | a.receivedTxns <- etx 159 | return nil 160 | } 161 | 162 | // Compute # of asset for a given bank according to the ledger. 163 | func (a *Auditor) computeSum(bank_i int) (*big.Int, bool) { 164 | Dprintf("[A] Auditing bank %v \n", bank_i) 165 | var rep AuditRep 166 | a.banks[bank_i].Audit(&struct{}{}, &rep) 167 | comms := zksigma.Zero 168 | rtokens := zksigma.Zero 169 | a.mu.Lock() 170 | if *useCache { 171 | comms = a.CommsCache[bank_i] 172 | rtokens = a.RTokenCache[bank_i] 173 | } else { 174 | for i := 0; i < len(a.local_ledger.Transactions); i++ { 175 | etx := &a.local_ledger.Transactions[i] 176 | if etx.Type == Transfer { 177 | comms = ZKLedgerCurve.Add(comms, etx.Entries[bank_i].Comm) 178 | rtokens = ZKLedgerCurve.Add(rtokens, etx.Entries[bank_i].RToken) 179 | } else if (etx.Type == Issuance || etx.Type == Withdrawal) && etx.Sender == bank_i { 180 | gval := ZKLedgerCurve.Mult(ZKLedgerCurve.G, etx.Entries[etx.Sender].V) 181 | comms = ZKLedgerCurve.Add(comms, gval) 182 | } 183 | } 184 | } 185 | a.mu.Unlock() 186 | gv := ZKLedgerCurve.Neg(ZKLedgerCurve.Mult(ZKLedgerCurve.G, rep.Sum)) // 1 / g^\sum{v_i} 187 | T := ZKLedgerCurve.Add(comms, gv) 188 | // TODO: Error handling 189 | verifies, _ := rep.Eproof.Verify(ZKLedgerCurve, T, rtokens, ZKLedgerCurve.H, a.pki.Get(bank_i)) 190 | if !verifies { 191 | Dprintf("[A] Bank %v proof didn't verify! Their total: %v\n", bank_i, rep.Sum) 192 | Dprintf(" My \\sum{rtks_i}: %v\n", rtokens) 193 | Dprintf(" My \\sum{comms_i}: %v\n", comms) 194 | Dprintf(" gv: %v\n", gv) 195 | Dprintf(" T: %v\n", T) 196 | } 197 | return rep.Sum, verifies 198 | } 199 | 200 | // Should hold a.mu. OK to call in parallel for different banks. 201 | func (a *Auditor) sumOneBank(wg *sync.WaitGroup, bank_i int, totals []*big.Int, cache bool) { 202 | var rep AuditRep 203 | a.banks[bank_i].Audit(&struct{}{}, &rep) 204 | comms := zksigma.Zero 205 | rtokens := zksigma.Zero 206 | if *useCache && cache { 207 | comms = a.CommsCache[bank_i] 208 | rtokens = a.RTokenCache[bank_i] 209 | } else { 210 | for i := 0; i < len(a.local_ledger.Transactions); i++ { 211 | etx := &a.local_ledger.Transactions[i] 212 | if etx.Type == Transfer { 213 | comms = ZKLedgerCurve.Add(comms, etx.Entries[bank_i].Comm) 214 | rtokens = ZKLedgerCurve.Add(rtokens, etx.Entries[bank_i].RToken) 215 | } else if (etx.Type == Issuance || etx.Type == Withdrawal) && etx.Sender == bank_i { 216 | gval := ZKLedgerCurve.Mult(ZKLedgerCurve.G, etx.Entries[etx.Sender].V) 217 | comms = ZKLedgerCurve.Add(comms, gval) 218 | } 219 | } 220 | } 221 | gv := ZKLedgerCurve.Neg(ZKLedgerCurve.Mult(ZKLedgerCurve.G, rep.Sum)) // 1 / g^\sum{v_i} 222 | T := ZKLedgerCurve.Add(comms, gv) 223 | // TODO: Error handling 224 | verifies, _ := rep.Eproof.Verify(ZKLedgerCurve, T, rtokens, ZKLedgerCurve.H, a.pki.Get(bank_i)) 225 | if !verifies { 226 | Dprintf("[A] Bank %v proof didn't verify! Their total: %v\n", bank_i, rep.Sum) 227 | Dprintf(" My \\sum{rtks_i}: %v\n", rtokens) 228 | Dprintf(" My \\sum{comms_i}: %v\n", comms) 229 | Dprintf(" gv: %v\n", gv) 230 | Dprintf(" T: %v\n", T) 231 | } 232 | totals[bank_i] = rep.Sum 233 | wg.Done() 234 | } 235 | 236 | func (a *Auditor) Herfindahl(cache bool, _ *struct{}) (*big.Rat, error) { 237 | <-a.Setup 238 | totals := make([]*big.Int, a.num) 239 | total := big.NewInt(0) 240 | concentrations := make([]*big.Rat, a.num) 241 | var wg sync.WaitGroup 242 | a.mu.Lock() 243 | defer a.mu.Unlock() 244 | wg.Add(a.num) 245 | for i := 0; i < a.num; i++ { 246 | go a.sumOneBank(&wg, i, totals, cache) 247 | concentrations[i] = new(big.Rat) 248 | } 249 | wg.Wait() 250 | for i := 0; i < a.num; i++ { 251 | total.Add(total, totals[i]) 252 | } 253 | Dprintf("[A] Herfindahl: %v totals, %v total\n", totals, total) 254 | hIndex := big.NewRat(0, 1) 255 | for i := 0; i < a.num; i++ { 256 | marketShare := new(big.Rat).Quo(new(big.Rat).SetInt(totals[i]), new(big.Rat).SetInt(total)) 257 | 258 | hIndex.Add(hIndex, new(big.Rat).Mul(marketShare, marketShare)) // add the sum of squares of the market share 259 | } 260 | return hIndex, nil 261 | } 262 | 263 | // Compute # of asset for a given bank according to unencrypted test 264 | // values in the ledger. ONLY TO BE USED FOR TESTING. 265 | func (a *Auditor) computeClearSum(bank_i int) *big.Int { 266 | total := big.NewInt(0) 267 | for i := 0; i < len(a.local_ledger.Transactions); i++ { 268 | total.Add(total, a.local_ledger.Transactions[i].Entries[bank_i].V) 269 | } 270 | return total 271 | } 272 | 273 | // Compute # total outstanding of an asset. 274 | func (a *Auditor) computeOutstanding() *big.Int { 275 | total := big.NewInt(0) 276 | for i := 0; i < a.num; i++ { 277 | v, err := a.computeSum(i) 278 | if !err { 279 | log.Fatalf("Commitments and rvals did not match for bank %v\n", i) 280 | } 281 | total.Add(total, v) 282 | } 283 | return total 284 | } 285 | 286 | func (a *Auditor) Audit(_ *struct{}, _ *struct{}) *big.Int { 287 | <-a.Setup 288 | Dprintf("[A] Auditing all banks \n") 289 | return a.computeOutstanding() 290 | } 291 | 292 | func (a *Auditor) GetNumTX(_ *struct{}, _ *struct{}) int { 293 | return len(a.local_ledger.Transactions) 294 | } 295 | 296 | // X Amount of some risky thing outstanding (outstanding sum) 297 | // X Amount of some risky thing at one bank (sum) 298 | // - Aggregate risk exposures (outstanding sum?) 299 | // X Herfindahl concentration index 300 | // - Aggregate leverage 301 | // - Margin-to-equity ratios 302 | // - Leverage ratios 303 | // - Average correlations between *changes* in securities holdings 304 | -------------------------------------------------------------------------------- /audit_test.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "testing" 7 | "time" 8 | ) 9 | 10 | func TestSimpleSumAudit(t *testing.T) { 11 | error := false 12 | s := SetupTest(2, 1, 500) 13 | defer FinishTest(s) 14 | if len(s.L.Transactions) != 3 { 15 | t.Errorf("Ledger Process() didn't work") 16 | error = true 17 | } 18 | bank_val, _ := s.B[1].answerSum() 19 | audit_val, x := s.A.computeSum(1) 20 | if x != true { 21 | t.Fatalf("Auditing did not work out! Bank:%v Auditor:%v", bank_val, audit_val) 22 | error = true 23 | } 24 | tmp := big.NewInt(600) 25 | if audit_val.Cmp(tmp) != 0 { 26 | t.Fatalf("Bad audit value, should be 600 auditor: %v\n", audit_val) 27 | } 28 | if audit_val.Cmp(bank_val) != 0 { 29 | t.Fatalf("Mismatched answers to sum for bank 1, should be 600 auditor: %v, bank: %v\n", 30 | audit_val, bank_val) 31 | error = true 32 | } 33 | 34 | bank_val, _ = s.B[0].answerSum() 35 | audit_val, x = s.A.computeSum(0) 36 | if x != true { 37 | t.Fatalf("Auditing did not work out! Bank:%v Auditor:%v", bank_val, audit_val) 38 | error = true 39 | } 40 | if audit_val.Cmp(big.NewInt(400)) != 0 { 41 | t.Fatalf("Bad audit value, should be 400 auditor: %v\n", audit_val) 42 | error = true 43 | } 44 | if audit_val.Cmp(bank_val) != 0 { 45 | t.Fatalf("Mismatched answers to sum for bank 0, should be -100 auditor: %v, bank: %v\n", 46 | audit_val, bank_val) 47 | error = true 48 | } 49 | if !error { 50 | fmt.Printf("Passed TestSimpleSumAudit\n") 51 | } 52 | } 53 | 54 | func TestAuditWithIssuance(t *testing.T) { 55 | error := false 56 | s := SetupTest(2, 0, 50) 57 | defer FinishTest(s) 58 | v := big.NewInt(50) 59 | //s.B[0].Issue(v) 60 | time.Sleep(20 * time.Millisecond) 61 | bank_val, _ := s.B[0].answerSum() 62 | audit_val, x := s.A.computeSum(0) 63 | if x != true { 64 | t.Fatalf("Auditing did not work out! Bank:%v Auditor:%v", bank_val, audit_val) 65 | error = true 66 | } 67 | if audit_val.Cmp(v) != 0 { 68 | t.Fatalf("Bad audit value, should be 50 auditor: %v\n", audit_val) 69 | } 70 | if audit_val.Cmp(bank_val) != 0 { 71 | t.Fatalf("Mismatched answers to sum for bank 0, should be 50 auditor: %v, bank: %v\n", 72 | audit_val, bank_val) 73 | error = true 74 | } 75 | v = big.NewInt(25) 76 | s.B[0].CreateEncryptedTransaction(1, v) 77 | time.Sleep(20 * time.Millisecond) 78 | bank_val, _ = s.B[0].answerSum() 79 | audit_val, x = s.A.computeSum(0) 80 | if x != true { 81 | t.Fatalf("Auditing did not work out! Bank:%v Auditor:%v", bank_val, audit_val) 82 | error = true 83 | } 84 | if audit_val.Cmp(v) != 0 { 85 | t.Fatalf("Bad audit value, should be 25 auditor: %v\n", audit_val) 86 | } 87 | if audit_val.Cmp(bank_val) != 0 { 88 | t.Fatalf("Mismatched answers to sum for bank 0, should be 25 auditor: %v, bank: %v\n", 89 | audit_val, bank_val) 90 | error = true 91 | } 92 | 93 | if !error { 94 | fmt.Printf("Passed TestAuditWithIssuance\n") 95 | } 96 | } 97 | 98 | func TestHerfindahl(t *testing.T) { 99 | s := SetupTest(2, 0, 10) 100 | defer FinishTest(s) 101 | hIndex, err := s.A.Herfindahl(true, nil) 102 | if err != nil { 103 | t.Fatalf("Couldn't calculate concentrations some bank didn't verify\n") 104 | } 105 | if hIndex.Cmp(big.NewRat(1, 2)) != 0 { 106 | t.Fatalf("Banks do not have right Herfindahl Index %v\n", hIndex) 107 | } 108 | 109 | fmt.Println("Passed TestHerfindahl") 110 | } 111 | 112 | func TestBadAudit(t *testing.T) { 113 | s := SetupTest(2, 1, 500) 114 | defer FinishTest(s) 115 | if len(s.L.Transactions) != 3 { 116 | t.Errorf("Ledger Process() didn't work") 117 | } 118 | 119 | // Reach in and change the bank's answer 120 | tmp := big.NewInt(2) 121 | var tx *Transaction 122 | for _, v := range s.B[1].transactions { 123 | tx = v 124 | break 125 | } 126 | tx.value.Set(tmp) 127 | s.B[1].ValueCache.Set(tmp) 128 | 129 | bank_val, _ := s.B[1].answerSum() 130 | audit_val, x := s.A.computeSum(1) 131 | if x == true { 132 | t.Fatalf("Auditing should have failed %v %v", bank_val, audit_val) 133 | } 134 | if audit_val.Cmp(tmp) != 0 { 135 | t.Fatalf("Bad audit value, should be 2 auditor: %v\n", audit_val) 136 | } 137 | if audit_val.Cmp(bank_val) < 0 { 138 | t.Fatalf("Mismatched answers to sum for bank 1, should be 2 auditor: %v, bank: %v\n", 139 | audit_val, bank_val) 140 | } 141 | fmt.Printf("Passed TestBadAudit\n") 142 | } 143 | 144 | func TestThreeBankAudit(t *testing.T) { 145 | nb := 3 146 | ntx := 2 147 | initialAmount := 500 148 | s := SetupTest(nb, ntx, int64(initialAmount)) 149 | defer FinishTest(s) 150 | if len(s.L.Transactions) != (ntx + nb) { 151 | t.Errorf("Ledger Process() didn't work") 152 | } 153 | for i := 0; i < nb; i++ { 154 | if len(s.B[i].local_ledger.Transactions) != ntx+nb { 155 | t.Fatalf("Bank %v has not gotten all %v transactions. Has %v", i, nb+ntx, len(s.B[i].local_ledger.Transactions)) 156 | } 157 | } 158 | audit_val, x := s.A.computeSum(0) 159 | if x != true { 160 | for i := 0; i < nb; i++ { 161 | s.B[i].print_transactions() 162 | } 163 | t.Fatalf("Auditing failed %v", audit_val) 164 | } 165 | fmt.Printf("Passed TestThreeBankAudit\n") 166 | } 167 | 168 | func benchmarkClearSum(rows int, b *testing.B) { 169 | s := SetupTest(10, rows, 500) 170 | defer FinishTest(s) 171 | b.ResetTimer() 172 | for i := 0; i < b.N; i++ { 173 | audit := i % 10 174 | s.A.computeClearSum(audit) 175 | } 176 | } 177 | 178 | func BenchmarkClearSum1000x(b *testing.B) { benchmarkClearSum(1000, b) } 179 | func BenchmarkClearSum10000(b *testing.B) { benchmarkClearSum(10000, b) } 180 | 181 | func benchmarkEncSum(rows int, b *testing.B) { 182 | s := SetupTest(10, rows, 500) 183 | defer FinishTest(s) 184 | b.ResetTimer() 185 | for i := 0; i < b.N; i++ { 186 | audit := i % 10 187 | s.A.computeSum(audit) 188 | } 189 | } 190 | 191 | func BenchmarkEncSum100x(b *testing.B) { benchmarkEncSum(100, b) } 192 | func BenchmarkEncSum1000x(b *testing.B) { benchmarkEncSum(1000, b) } 193 | func xBenchmarkEncSum10000(b *testing.B) { benchmarkEncSum(10000, b) } 194 | -------------------------------------------------------------------------------- /bank.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "math/big" 8 | "net" 9 | "net/rpc" 10 | "sync" 11 | "time" 12 | 13 | "github.com/mit-dci/zksigma" 14 | ) 15 | 16 | const ( 17 | TXN_BUFFER = 100 18 | ) 19 | 20 | var useCache = flag.Bool("useCache", true, "Use cached sums when auditing") 21 | var rpOutside = flag.Bool("rp", true, "Generate 0 Range Proofs outside of lock") 22 | var waitAppend = flag.Bool("wa", true, "Whether or not to wait for the AppendTxn to return") 23 | var emptyTxn = flag.Bool("et", false, "Send around empty txns and no verifying") 24 | 25 | func SetupLocalBanks(n int, l LedgerClient, pki *PKI) []*Bank { 26 | allbanks := make([]*Bank, n) 27 | for i := 0; i < n; i++ { 28 | allbanks[i] = MakeBank(i, n, l, pki) 29 | } 30 | for i := 0; i < n; i++ { 31 | allbanks[i].banks = make([]BankClient, n) 32 | for j := 0; j < n; j++ { 33 | allbanks[i].banks[j] = allbanks[j] 34 | } 35 | } 36 | return allbanks 37 | } 38 | 39 | // All transactions I'm involved with 40 | type Transaction struct { 41 | ts time.Time 42 | index int 43 | sender int 44 | receiver int // For now, assume single sender and receiver 45 | value *big.Int 46 | r *big.Int 47 | } 48 | 49 | type Bank struct { 50 | id int 51 | num int 52 | pki *PKI 53 | mu *sync.Mutex 54 | 55 | local_ledger *LocalLedger 56 | 57 | // Unencrypted versions of my sent and received transactions so I 58 | // can compute things for the auditor 59 | transactions map[int]*Transaction 60 | 61 | // Running total of the sum of the commitments for everyone in all 62 | // previous rows (this should be per asset) 63 | CommsCache []zksigma.ECPoint 64 | 65 | // Running total of my assets (this should be per asset) 66 | ValueCache *big.Int 67 | 68 | // Running total of the sum of the rtokens for everyone in all 69 | // previous rows (this should be per asset) 70 | RTokenCache []zksigma.ECPoint 71 | 72 | lastSeen int 73 | receivedTxns chan *EncryptedTransaction 74 | 75 | Done chan bool 76 | ledger LedgerClient 77 | banks []BankClient 78 | issuer IssuerClient 79 | 80 | Inflight map[int]chan struct{} 81 | Setup chan struct{} 82 | When int 83 | Waiter chan struct{} 84 | StoreRequests map[int]*StoreArgs 85 | } 86 | 87 | func MakeBank(id int, num int, l LedgerClient, pki *PKI) *Bank { 88 | b := &Bank{ 89 | id: id, 90 | num: num, 91 | pki: pki, 92 | mu: new(sync.Mutex), 93 | local_ledger: MakeLocalLedger(), 94 | transactions: make(map[int]*Transaction), 95 | ledger: l, 96 | Done: make(chan bool), 97 | CommsCache: make([]zksigma.ECPoint, num), 98 | lastSeen: -1, 99 | receivedTxns: make(chan *EncryptedTransaction, TXN_BUFFER), 100 | ValueCache: big.NewInt(0), // TODO: Add initial assets to banks 101 | RTokenCache: make([]zksigma.ECPoint, num), 102 | Inflight: make(map[int]chan struct{}), 103 | Setup: make(chan struct{}), 104 | Waiter: make(chan struct{}), 105 | StoreRequests: make(map[int]*StoreArgs), 106 | } 107 | c := make(chan struct{}) 108 | b.Inflight[-1] = c 109 | close(c) 110 | 111 | for i := 0; i < num; i++ { 112 | b.CommsCache[i] = zksigma.Zero 113 | b.RTokenCache[i] = zksigma.Zero 114 | } 115 | go b.start() 116 | return b 117 | } 118 | 119 | func (b *Bank) log(str string, idx int, args ...interface{}) { 120 | x := fmt.Sprintf(str, args...) 121 | if idx > -1 { 122 | Dprintf("[%v][%v] %s", b.id, idx, x) 123 | } else { 124 | Dprintf("[%v] %s", b.id, x) 125 | } 126 | } 127 | 128 | func (b *Bank) listen(hostname string, basePort int) { 129 | listener, err := net.Listen("tcp", fmt.Sprintf(":%d", (basePort)+(b.id)+1)) 130 | if err != nil { 131 | log.Fatalf("[%v] Could not listen %v\n", b.id, err) 132 | } 133 | err = rpc.Register(b) 134 | if err != nil { 135 | panic(err) 136 | } 137 | for { 138 | conn, err := listener.Accept() 139 | if err != nil { 140 | fmt.Println(err) 141 | continue 142 | } 143 | go rpc.ServeConn(conn) 144 | } 145 | } 146 | 147 | func (b *Bank) Go(c APLClientConfig, _ *struct{}) error { 148 | go b.register(c.Hostname, c.BasePort, c.BankHostnames, c.LedgerHostname) 149 | b.listen(c.Hostname, c.BasePort) 150 | return nil 151 | } 152 | 153 | func (b *Bank) register(hostname string, basePort int, bankHostnames []string, ledgerHostname string) { 154 | var wg sync.WaitGroup 155 | b.banks = make([]BankClient, b.num) 156 | for i := 0; i < b.num; i++ { 157 | if i == b.id { 158 | continue 159 | } 160 | wg.Add(1) 161 | go func(i int) { 162 | x := MakeRemoteBankClient() 163 | x.connect(bankHostnames[i], basePort+i+1) 164 | b.banks[i] = x 165 | wg.Done() 166 | }(i) 167 | } 168 | wg.Add(1) 169 | go func() { 170 | x := MakeRemoteLedgerClient() 171 | x.Connect(ledgerHostname, basePort) 172 | b.ledger = x 173 | wg.Done() 174 | }() 175 | wg.Wait() 176 | b.log("Registered with banks and ledger\n", -1) 177 | close(b.Setup) 178 | } 179 | 180 | func (b *Bank) start() { 181 | <-b.Setup 182 | Dprintf("[%v] Starting bank loop...\n", b.id) 183 | for { 184 | select { 185 | case etx := <-b.receivedTxns: 186 | b.log(" Received txn...\n", etx.Index) 187 | b.mu.Lock() 188 | lastSeen := b.lastSeen 189 | if etx.Index <= lastSeen { 190 | log.Fatalf("[%v][%v] lastSeen %v out of whack with received transaction\n", 191 | b.id, etx.Index, lastSeen) 192 | b.mu.Unlock() 193 | } else if etx.Index == lastSeen+1 { 194 | //b.log(" Received txn equal to lastSeen+1...\n", etx.Index) 195 | if !*emptyTxn { 196 | // I wonder: if this is *my* transaction, do I 197 | // need to verify it? I don't think I do, but how 198 | // can I be sure it really is my transaction? 199 | // Could keep a hash of etx's I create a round and 200 | // verify that it is the same one I created. 201 | // Future work. 202 | start := time.Now() 203 | if !etx.Verify(b.pki.PK, b.CommsCache, b.RTokenCache, fmt.Sprintf("%d", b.id)) { 204 | log.Fatalf("[%v] Bad transaction!\n", b.id) 205 | } 206 | b.log("time txn verify %v\n", etx.Index, time.Since(start)) 207 | } 208 | b.updateLocalData(etx) 209 | if b.When != 0 && etx.Index == b.When { 210 | b.log(" Closing waiter on txn %v...\n", etx.Index, etx.Index) 211 | close(b.Waiter) 212 | } 213 | b.mu.Unlock() 214 | } else { 215 | b.log(" Received txn out of order, expected %v\n", etx.Index, lastSeen+1) 216 | b.mu.Unlock() 217 | b.receivedTxns <- etx 218 | } 219 | case <-b.Done: 220 | Dprintf("[%v] Shutting down bank loop...%v left\n", b.id, len(b.receivedTxns)) 221 | close(b.receivedTxns) 222 | return 223 | } 224 | } 225 | } 226 | 227 | func (b *Bank) Stop(_ *struct{}, _ *struct{}) error { 228 | b.Done <- true 229 | return nil 230 | } 231 | 232 | func (b *Bank) DumpLedger(_ *struct{}, _ *struct{}) error { 233 | b.local_ledger.DumpReadableLedger(nil, nil) 234 | b.local_ledger.DumpLedger(nil, nil) 235 | return nil 236 | } 237 | 238 | func (b *Bank) print_transactions() { 239 | if !*DEBUG { 240 | return 241 | } 242 | Dprintf("[%v]\t{", b.id) 243 | for _, tx := range b.transactions { 244 | Dprintf("%v:[%v->%v, %v, %v] ", tx.index, tx.sender, tx.receiver, tx.value, tx.r) 245 | } 246 | Dprintf("}\n") 247 | Dprintf("[%v]\t commscache: %v\trtokencache: %v\tvaluecache: %v\n", b.id, b.CommsCache[b.id], b.RTokenCache[b.id], b.ValueCache) 248 | } 249 | 250 | type StoreArgs struct { 251 | TS time.Time 252 | I int 253 | C zksigma.ECPoint 254 | S int 255 | Re int 256 | V big.Int 257 | R big.Int 258 | } 259 | 260 | // Store the cleartext data from a transaction someone is sending me, 261 | // locally. A malicious bank might not give me the correct cleartext 262 | // data, in which case I would have to brute force the value. Not 263 | // implemented. 264 | // 265 | // I might get this *before* I process the encrypted transaction, in 266 | // which case, my value cache will be out of sync with my other 267 | // caches. So I'm going to wait till I process this transaction to 268 | // actually update my stores. Save this in a map! 269 | func (b *Bank) Store(req *StoreArgs, _ *struct{}) error { 270 | if !*emptyTxn { 271 | b.log(" .Saving %v value for %v from %v ...\n", req.I, req.V.Int64(), req.Re, req.S) 272 | b.StoreRequests[req.I] = req 273 | //return b.store_locally(req.TS, req.I, req.C, req.S, b.id, &req.V, &req.R) 274 | } 275 | return nil 276 | } 277 | 278 | // Add a transaction I've either sent or received to my store. Should hold mu 279 | func (b *Bank) store_locally(ts time.Time, index int, comm zksigma.ECPoint, sender int, receiver int, value *big.Int, r *big.Int) error { 280 | if *emptyTxn { 281 | return nil 282 | } 283 | b.log(" .Storing value %v from %v locally. ledger size: %v...\n", index, value, sender, len(b.transactions)) 284 | tx := Transaction{ 285 | ts: ts, 286 | index: index, 287 | receiver: receiver, 288 | value: value, 289 | sender: sender, 290 | r: r, // For debug purposes only. 291 | } 292 | b.transactions[index] = &tx 293 | b.ValueCache.Add(b.ValueCache, value) 294 | return nil 295 | } 296 | 297 | // Wait for the previous transaction to be processed. 298 | func (b *Bank) wait(idx int) { 299 | b.mu.Lock() 300 | c, ok := b.Inflight[idx-1] 301 | if !ok { 302 | // I'm the first person to need it. 303 | b.log("No one set up channel for waiters on txn(%v)\n", idx, idx-1) 304 | c = make(chan struct{}) 305 | b.Inflight[idx-1] = c 306 | } 307 | b.mu.Unlock() 308 | start := time.Now() 309 | <-c 310 | b.log("time c wait %v\n", idx, time.Since(start)) 311 | } 312 | 313 | func (b *Bank) Issue(value *big.Int, _ *struct{}) *EncryptedTransaction { 314 | <-b.Setup 315 | b.log("Starting ISSUE\n", -1) 316 | etx := &EncryptedTransaction{} 317 | // Might block, waiting for previous transaction to complete at 318 | // the ledger. 319 | start := time.Now() 320 | b.ledger.StartTxn(b.id, &etx.Index) 321 | b.log("time waiting to StartTxn %v\n", etx.Index, time.Since(start)) 322 | // Just because it completed at the ledger does not mean it was 323 | // processed. 324 | b.wait(etx.Index) 325 | start = time.Now() 326 | etx.Type = Issuance 327 | etx.Sender = b.id 328 | etx.Entries = make([]Entry, b.num) 329 | etx.Entries[b.id].V = value 330 | etx.TS = time.Now() 331 | // TODO: Use a proof of the issuer 332 | // TODO: Error handling 333 | proof, err := zksigma.NewGSPFSProofBase(ZKLedgerCurve, ZKLedgerCurve.H, b.pki.Get(len(b.banks)), b.pki.GetSK(len(b.banks))) // use the key of the issuer in order to create a new issuance 334 | if err != nil { 335 | log.Fatalf("Error creating SKProof for issue: %s", err.Error()) 336 | } 337 | etx.Entries[b.id].SKProof = proof 338 | b.mu.Lock() 339 | b.store_locally(etx.TS, etx.Index, etx.Entries[b.id].Comm, b.id, -1, value, nil) 340 | b.mu.Unlock() 341 | b.log("time Local %v\n", etx.Index, time.Since(start)) 342 | // Submit to global ledger 343 | b.log("Appending to ledger txn from b%v issuance amt %v\n", etx.Index, b.id, value) 344 | start = time.Now() 345 | b.ledger.AppendTxn(etx, nil) 346 | b.log("time AppendTxn %v\n", etx.Index, time.Since(start)) 347 | b.log("Appended to ledger txn from b%v issuance amt %v\n", etx.Index, b.id, value) 348 | return etx 349 | } 350 | 351 | func (b *Bank) Withdraw(value *big.Int, _ *struct{}) *EncryptedTransaction { 352 | <-b.Setup 353 | etx := &EncryptedTransaction{} 354 | // Might block, waiting for previous transaction to complete at 355 | // the ledger. 356 | start := time.Now() 357 | b.ledger.StartTxn(b.id, &etx.Index) 358 | b.log("time waiting to StartTxn %v\n", etx.Index, time.Since(start)) 359 | // Just because it completed at the ledger does not mean it was 360 | // processed. 361 | b.wait(etx.Index) 362 | b.log("Ready to start withdrawal\n", etx.Index) 363 | start = time.Now() 364 | etx.Type = Withdrawal 365 | etx.Sender = b.id 366 | etx.Entries = make([]Entry, b.num) 367 | etx.Entries[b.id].V = value 368 | etx.TS = time.Now() 369 | // TODO: Error handling 370 | proof, _ := zksigma.NewGSPFSProofBase(ZKLedgerCurve, ZKLedgerCurve.H, b.pki.Get(b.id), b.pki.GetSK(b.id)) 371 | etx.Entries[b.id].SKProof = proof 372 | b.mu.Lock() 373 | b.store_locally(etx.TS, etx.Index, etx.Entries[b.id].Comm, b.id, -1, value, nil) 374 | b.mu.Unlock() 375 | b.log("time Local %v\n", etx.Index, time.Since(start)) 376 | // Submit to global ledger 377 | b.log("Appending to ledger txn from b%v withdrawal amt %v\n", etx.Index, b.id, value) 378 | start = time.Now() 379 | b.ledger.AppendTxn(etx, nil) 380 | b.log("time AppendTxn %v\n", etx.Index, time.Since(start)) 381 | b.log("Appended to ledger txn from b%v withdrawal amt %v\n", etx.Index, b.id, value) 382 | return etx 383 | } 384 | 385 | func generateRangeProofs(num int, etx *EncryptedTransaction, bank_j int, id int, value *big.Int) { 386 | etx.Entries = make([]Entry, num) 387 | for i := 0; i < num; i++ { 388 | if i == id { 389 | continue 390 | } else if i == bank_j { 391 | // TODO: Error handling 392 | etx.Entries[i].RP, etx.Entries[i].BAuxR, _ = zksigma.NewRangeProof(ZKLedgerCurve, value) 393 | } else { 394 | // TODO: Error handling 395 | etx.Entries[i].RP, etx.Entries[i].BAuxR, _ = zksigma.NewRangeProof(ZKLedgerCurve, big.NewInt(0)) 396 | } 397 | } 398 | } 399 | 400 | // Create a transaction for sending to another bank 401 | func (b *Bank) CreateEncryptedTransaction(bank_j int, value *big.Int) *EncryptedTransaction { 402 | <-b.Setup 403 | if bank_j == b.id { 404 | log.Fatalf("[%v] Sending a transaction to myself (not supported)\n", b.id) 405 | } 406 | etx := &EncryptedTransaction{} 407 | 408 | startx := time.Now() 409 | start := time.Now() 410 | 411 | if *rpOutside && !*emptyTxn { 412 | // Pre-generate proofs 413 | generateRangeProofs(b.num, etx, bank_j, b.id, value) 414 | b.log("time to make %v RPs %v\n", -1, b.num-1, time.Since(start)) 415 | } 416 | 417 | // Might block, waiting for previous transaction to complete at 418 | // the ledger. 419 | start = time.Now() 420 | b.ledger.StartTxn(b.id, &etx.Index) 421 | b.log("time waiting to StartTxn %v\n", etx.Index, time.Since(start)) 422 | start2 := time.Now() 423 | 424 | // Just because it completed at the ledger does not mean I 425 | // processed the previous transaction. When this returns, it 426 | // means I've updated all of my local data caches to reflect 427 | // transaction etx.Index-1, so I'm ready to produce this one. 428 | b.wait(etx.Index) 429 | 430 | start = time.Now() 431 | 432 | var theirR *big.Int 433 | if !*emptyTxn { 434 | theirR = b.createLocal(etx, bank_j, value) 435 | b.log("time CreateLocal %v\n", etx.Index, time.Since(start)) 436 | } 437 | _ = theirR 438 | 439 | var args *StoreArgs 440 | if !*emptyTxn { 441 | // Send to bank_j for storing it locally. Have to do it here 442 | // because before the ledger lock I don't know the index; 443 | // after, it might be too late and the receiver will process 444 | // the txn not even knowing he got funds. 445 | args = &StoreArgs{TS: etx.TS, I: etx.Index, C: etx.Entries[bank_j].Comm, S: b.id, Re: bank_j, V: *value, R: *theirR} 446 | } 447 | start = time.Now() 448 | b.banks[bank_j].Store(args, nil) 449 | b.log("time Store %v\n", etx.Index, time.Since(start)) 450 | 451 | // Submit to global ledger 452 | b.log("Appending to ledger txn from b%v to b%v amt %v\n", etx.Index, b.id, bank_j, value) 453 | start = time.Now() 454 | if *waitAppend { 455 | b.ledger.AppendTxn(etx, nil) 456 | b.log("time AppendTxn call %v\n", etx.Index, time.Since(start)) 457 | } else { 458 | go func(start time.Time) { 459 | b.ledger.AppendTxn(etx, nil) 460 | b.log("time AppendTxn call (didn't wait) %v\n", etx.Index, time.Since(start)) 461 | }(start) 462 | } 463 | b.log("time with Ledger lock %v\n", etx.Index, time.Since(start2)) 464 | b.log("time total CreateEncryptedTxn %v\n", etx.Index, time.Since(startx)) 465 | 466 | return etx 467 | } 468 | 469 | // All-local create transaction function 470 | func (b *Bank) createLocal(etx *EncryptedTransaction, bank_j int, value *big.Int) *big.Int { 471 | var myR *big.Int 472 | var theirR *big.Int 473 | var tmpR *big.Int 474 | var commaux zksigma.ECPoint 475 | var rp *big.Int 476 | var rtoken zksigma.ECPoint 477 | var baux zksigma.ECPoint 478 | vn := new(big.Int).Neg(value) 479 | totalR := big.NewInt(0) 480 | etx.Sender = b.id // testing 481 | etx.Receiver = bank_j // testing 482 | 483 | // Sometimes I create this before createLocal, for example when 484 | // pre-generating range proofs. Sometimes not (current tests) 485 | if len(etx.Entries) == 0 { 486 | etx.Entries = make([]Entry, b.num) 487 | } 488 | etx.TS = time.Now() 489 | for i := 0; i < b.num; i++ { 490 | etx.Entries[i].Bank = i 491 | if i == bank_j { 492 | // Commit to value 493 | // we want all commitments to add up to identity of group, so we choose 494 | // the last randomness to be N-sumSoFar 495 | if i == b.num-1 { 496 | theirR = new(big.Int).Sub(ZKLedgerCurve.C.Params().N, totalR) 497 | theirR.Mod(theirR, ZKLedgerCurve.C.Params().N) 498 | etx.Entries[i].Comm = zksigma.PedCommitR(ZKLedgerCurve, value, theirR) 499 | //fmt.Println("Last entry in TX", b.num) 500 | } else { 501 | // TODO: Error handling 502 | etx.Entries[i].Comm, theirR, _ = zksigma.PedCommit(ZKLedgerCurve, value) 503 | } 504 | 505 | etx.Entries[i].V = value // testing 506 | etx.Entries[i].R = theirR // testing 507 | tmpR = theirR 508 | rtoken = zksigma.CommitR(ZKLedgerCurve, b.pki.Get(i), tmpR) 509 | 510 | // Range Proof to get randomness value to use 511 | if !*rpOutside { 512 | // TODO: Error Handling 513 | etx.Entries[i].RP, rp, _ = zksigma.NewRangeProof(ZKLedgerCurve, value) 514 | } else { 515 | // Otherwise, Range Proof done before 516 | rp = etx.Entries[i].BAuxR 517 | } 518 | // cm_{aux,i} ~ cm 519 | commaux = zksigma.PedCommitR(ZKLedgerCurve, value, rp) 520 | etx.Entries[i].CommAux = commaux 521 | baux = zksigma.CommitR(ZKLedgerCurve, b.pki.Get(i), rp) 522 | rpmr := new(big.Int).Sub(rp, theirR) 523 | rpmr.Mod(rpmr, ZKLedgerCurve.C.Params().N) 524 | 525 | // items for simulated proof 526 | b.mu.Lock() 527 | SA := ZKLedgerCurve.Add(b.CommsCache[i], etx.Entries[i].Comm) 528 | SB := ZKLedgerCurve.Add(b.RTokenCache[i], rtoken) 529 | b.mu.Unlock() 530 | Base1 := ZKLedgerCurve.Add(commaux, ZKLedgerCurve.Neg(SA)) // Base1 = CommAux - (\Sum_{i=0}^{n-1} CM_i + CM_n) 531 | Result1 := ZKLedgerCurve.Add(baux, ZKLedgerCurve.Neg(SB)) // Result1 = Baux - SB 532 | Result2 := ZKLedgerCurve.Add(commaux, ZKLedgerCurve.Neg(etx.Entries[i].Comm)) 533 | 534 | // TODO: Error handling 535 | etx.Entries[i].Assets, _ = zksigma.NewDisjunctiveProof(ZKLedgerCurve, Base1, Result1, ZKLedgerCurve.H, Result2, rpmr, 1) 536 | etx.Entries[i].CommConsistency, _ = zksigma.NewConsistencyProof(ZKLedgerCurve, etx.Entries[i].Comm, rtoken, b.pki.Get(bank_j), value, tmpR) 537 | etx.Entries[i].AuxConsistency, _ = zksigma.NewConsistencyProof(ZKLedgerCurve, commaux, baux, b.pki.Get(bank_j), value, rp) 538 | } else if i == b.id { 539 | // Commit to negative value 540 | if i == b.num-1 { 541 | myR = new(big.Int).Sub(ZKLedgerCurve.C.Params().N, totalR) 542 | myR.Mod(myR, ZKLedgerCurve.C.Params().N) 543 | etx.Entries[i].Comm = zksigma.PedCommitR(ZKLedgerCurve, vn, myR) 544 | 545 | //fmt.Println("Last entry in TX", b.num) 546 | } else { 547 | // TODO: Error handling 548 | etx.Entries[i].Comm, myR, _ = zksigma.PedCommit(ZKLedgerCurve, vn) 549 | } 550 | etx.Entries[i].V = vn // testing 551 | etx.Entries[i].R = myR // testing 552 | tmpR = myR 553 | rtoken = zksigma.CommitR(ZKLedgerCurve, b.pki.Get(i), tmpR) 554 | b.mu.Lock() 555 | sum := new(big.Int).Add(vn, b.ValueCache) 556 | b.mu.Unlock() 557 | // TODO: Error Handling 558 | etx.Entries[i].RP, rp, _ = zksigma.NewRangeProof(ZKLedgerCurve, sum) 559 | 560 | baux = zksigma.CommitR(ZKLedgerCurve, b.pki.Get(i), rp) 561 | b.mu.Lock() 562 | // I shouldn't even be here unless the local data 563 | // structures have been updated from the n-1th 564 | // transaction, because I should have been stuck in the wait() 565 | 566 | SA := ZKLedgerCurve.Add(b.CommsCache[i], etx.Entries[i].Comm) // SA = n-1 sum + curSum 567 | SB := ZKLedgerCurve.Add(b.RTokenCache[i], rtoken) //SB = n-1 sum + current rtoken 568 | b.mu.Unlock() 569 | 570 | commaux = zksigma.PedCommitR(ZKLedgerCurve, sum, rp) 571 | etx.Entries[i].CommAux = commaux 572 | Base1 := ZKLedgerCurve.Add(commaux, ZKLedgerCurve.Neg(SA)) 573 | Result1 := ZKLedgerCurve.Add(baux, ZKLedgerCurve.Neg(SB)) // Result1 = commaux - (sum of entries) 574 | Result2 := ZKLedgerCurve.Add(commaux, ZKLedgerCurve.Neg(etx.Entries[i].Comm)) 575 | 576 | // TODO: Error handling 577 | etx.Entries[i].Assets, _ = zksigma.NewDisjunctiveProof(ZKLedgerCurve, Base1, Result1, ZKLedgerCurve.H, Result2, b.pki.GetSK(b.id), 0) 578 | etx.Entries[i].CommConsistency, _ = zksigma.NewConsistencyProof(ZKLedgerCurve, etx.Entries[i].Comm, rtoken, b.pki.Get(i), vn, tmpR) 579 | etx.Entries[i].AuxConsistency, _ = zksigma.NewConsistencyProof(ZKLedgerCurve, commaux, baux, b.pki.Get(i), sum, rp) 580 | } else { 581 | // Commit to 0 582 | if i == b.num-1 { 583 | tmpR = new(big.Int).Sub(ZKLedgerCurve.C.Params().N, totalR) 584 | tmpR.Mod(tmpR, ZKLedgerCurve.C.Params().N) 585 | etx.Entries[i].Comm = zksigma.PedCommitR(ZKLedgerCurve, big.NewInt(0), tmpR) 586 | //fmt.Println("Last entry in TX", b.num) 587 | } else { 588 | // TODO: Error Handling 589 | etx.Entries[i].Comm, tmpR, _ = zksigma.PedCommit(ZKLedgerCurve, big.NewInt(0)) 590 | } 591 | 592 | etx.Entries[i].V = big.NewInt(0) // testing 593 | etx.Entries[i].R = tmpR // testing 594 | 595 | if !*rpOutside { 596 | // TODO: Error Handling 597 | etx.Entries[i].RP, rp, _ = zksigma.NewRangeProof(ZKLedgerCurve, big.NewInt(0)) 598 | } else { 599 | // Otherwise, Range Proof done before 600 | rp = etx.Entries[i].BAuxR 601 | } 602 | if rp == nil { 603 | panic("rp is null") 604 | } 605 | // cm_{aux,i} ~ cm 606 | commaux = zksigma.PedCommitR(ZKLedgerCurve, big.NewInt(0), rp) 607 | etx.Entries[i].CommAux = commaux 608 | rtoken = zksigma.CommitR(ZKLedgerCurve, b.pki.Get(i), tmpR) 609 | baux = zksigma.CommitR(ZKLedgerCurve, b.pki.Get(i), rp) 610 | rpmr := new(big.Int).Sub(rp, tmpR) 611 | rpmr.Mod(rpmr, ZKLedgerCurve.C.Params().N) 612 | 613 | b.mu.Lock() 614 | SA := ZKLedgerCurve.Add(b.CommsCache[i], etx.Entries[i].Comm) 615 | SB := ZKLedgerCurve.Add(b.RTokenCache[i], rtoken) 616 | b.mu.Unlock() 617 | Base1 := ZKLedgerCurve.Add(commaux, ZKLedgerCurve.Neg(SA)) 618 | Result1 := ZKLedgerCurve.Add(baux, ZKLedgerCurve.Neg(SB)) 619 | Result2 := ZKLedgerCurve.Add(commaux, ZKLedgerCurve.Neg(etx.Entries[i].Comm)) 620 | 621 | // TODO: Error handling 622 | etx.Entries[i].Assets, _ = zksigma.NewDisjunctiveProof(ZKLedgerCurve, Base1, Result1, ZKLedgerCurve.H, Result2, rpmr, 1) 623 | etx.Entries[i].CommConsistency, _ = zksigma.NewConsistencyProof(ZKLedgerCurve, etx.Entries[i].Comm, rtoken, b.pki.Get(i), big.NewInt(0), tmpR) 624 | etx.Entries[i].AuxConsistency, _ = zksigma.NewConsistencyProof(ZKLedgerCurve, commaux, baux, b.pki.Get(i), big.NewInt(0), rp) 625 | } 626 | totalR = totalR.Add(totalR, tmpR) 627 | etx.Entries[i].RToken = rtoken 628 | etx.Entries[i].BAux = baux 629 | } 630 | 631 | // Add to my own local store. At the moment, I expect appending 632 | // to the global ledger won't fail, and it will have the index I 633 | // expect, so I go ahead and do this now. 634 | 635 | var args *StoreArgs 636 | if !*emptyTxn { 637 | // Put in map to eventually store locally 638 | args = &StoreArgs{TS: etx.TS, I: etx.Index, C: etx.Entries[b.id].Comm, S: b.id, Re: bank_j, V: *vn, R: *myR} 639 | } 640 | b.Store(args, nil) 641 | return theirR 642 | } 643 | 644 | // The ledger is broadcasting a new transaction (it could be one of 645 | // mine, but if so I should have stored it locally already) 646 | func (b *Bank) Notify(etx *EncryptedTransaction, _ *struct{}) error { 647 | //b.log("Notified of txn\n", etx.Index) 648 | b.receivedTxns <- etx 649 | return nil 650 | } 651 | 652 | // Update local copy of ledger and commitment caches, and cleartext 653 | // data structures for a transaction that has been confirmed on the 654 | // ledger. Note that if I created the transaction I might have 655 | // updated them earlier. 656 | // 657 | // When done, wake up someone who might be waiting to create the next 658 | // transaction. 659 | // 660 | // Should hold mu. 661 | func (b *Bank) updateLocalData(etx *EncryptedTransaction) { 662 | b.log(" Processing txn and adding it to local ledger...\n", etx.Index) 663 | if !*emptyTxn { 664 | etx.reduce() 665 | b.local_ledger.add(etx) 666 | if etx.Type == Transfer { 667 | for i := 0; i < b.num; i++ { 668 | b.RTokenCache[i] = ZKLedgerCurve.Add(b.RTokenCache[i], etx.Entries[i].RToken) 669 | b.CommsCache[i] = ZKLedgerCurve.Add(b.CommsCache[i], etx.Entries[i].Comm) 670 | } 671 | req, ok := b.StoreRequests[etx.Index] 672 | if !ok { 673 | // No saved store request 674 | } else { 675 | b.store_locally(req.TS, req.I, req.C, req.S, req.Re, &req.V, &req.R) 676 | } 677 | } else if etx.Type == Issuance || etx.Type == Withdrawal { 678 | // Only one bank 679 | en := &etx.Entries[etx.Sender] 680 | gval := ZKLedgerCurve.Mult(ZKLedgerCurve.G, en.V) 681 | b.CommsCache[etx.Sender] = ZKLedgerCurve.Add(b.CommsCache[etx.Sender], gval) 682 | } 683 | } 684 | // Processed transaction etx.Index, signal whoever might be waiting for it. 685 | c, ok := b.Inflight[etx.Index] 686 | if !ok { 687 | // This might happen because no one at this bank is waiting 688 | // for etx.Index, cause it's not making more transactions. 689 | // Totally OK. I didn't know this was coming! 690 | c = make(chan struct{}) 691 | b.Inflight[etx.Index] = c 692 | } 693 | close(c) 694 | // Inform the next transaction who might be waiting for me later. 695 | _, ok = b.Inflight[etx.Index+1] 696 | if !ok { 697 | b.log(" Making channel for next waiter (on %v)\n", etx.Index, etx.Index+1) 698 | b.Inflight[etx.Index+1] = make(chan struct{}) 699 | } else { 700 | b.log(" Someone already made a channel for next waiter (on %v)\n", etx.Index, etx.Index+1) 701 | } 702 | b.lastSeen = b.lastSeen + 1 703 | // b.log("Processed txn\n", etx.Index) 704 | // Done processing transaction etx.Index 705 | } 706 | 707 | type AuditRep struct { 708 | Sum *big.Int 709 | Eproof *zksigma.EquivalenceProof 710 | } 711 | 712 | func (b *Bank) Audit(a *struct{}, rep *AuditRep) error { 713 | <-b.Setup 714 | rep.Sum, rep.Eproof = b.answerSum() 715 | return nil 716 | } 717 | 718 | type ComplexReq struct { 719 | } 720 | 721 | type ComplexRep struct { 722 | Recommitments []zksigma.ECPoint 723 | } 724 | 725 | func (b *Bank) ComplexAudit(req *ComplexReq, rep *ComplexRep) error { 726 | <-b.Setup 727 | for i := 0; i < len(b.local_ledger.Transactions); i++ { 728 | etx := &b.local_ledger.Transactions[i] 729 | tx, ok := b.transactions[etx.Index] 730 | _ = tx 731 | if !ok { 732 | // Not my transaction 733 | continue 734 | } 735 | if etx.Type == Transfer { 736 | } else if (etx.Type == Issuance || etx.Type == Withdrawal) && etx.Sender == b.id { 737 | } 738 | } 739 | return nil 740 | } 741 | 742 | func (b *Bank) answerSum() (*big.Int, *zksigma.EquivalenceProof) { 743 | b.mu.Lock() 744 | // return total quantity of asset, plus proof of knowledge 745 | total_comms := zksigma.Zero // Will be g^\sum{v_i}*h^\sum{r_i} 746 | total_rtoken := zksigma.Zero // Will be h^\sum{r_i}^sk 747 | total_clear := b.answerClearSum() // \sum{v_i} 748 | if *useCache { 749 | total_comms = b.CommsCache[b.id] 750 | total_rtoken = b.RTokenCache[b.id] 751 | } else { 752 | for i := 0; i < len(b.local_ledger.Transactions); i++ { 753 | etx := &b.local_ledger.Transactions[i] 754 | if etx.Type == Transfer { 755 | total_comms = ZKLedgerCurve.Add(total_comms, etx.Entries[b.id].Comm) 756 | total_rtoken = ZKLedgerCurve.Add(total_rtoken, etx.Entries[b.id].RToken) 757 | } else if (etx.Type == Issuance || etx.Type == Withdrawal) && etx.Sender == b.id { 758 | gval := ZKLedgerCurve.Mult(ZKLedgerCurve.G, etx.Entries[etx.Sender].V) 759 | total_comms = ZKLedgerCurve.Add(total_comms, gval) 760 | } 761 | } 762 | } 763 | b.print_transactions() 764 | b.mu.Unlock() 765 | gv := ZKLedgerCurve.Neg(ZKLedgerCurve.Mult(ZKLedgerCurve.G, total_clear)) // 1 / g^\sum{v_i} 766 | T := ZKLedgerCurve.Add(total_comms, gv) // should be h^r 767 | Dprintf("[%v] Audit:\n", b.id) 768 | Dprintf("[%v] \\sum{v_i}: %v\n", b.id, total_clear) 769 | Dprintf("[%v] 1 /g^\\sum{v_i}: %v\n", b.id, gv) 770 | Dprintf("[%v] \\sum{comms_i}: %v\n", b.id, total_comms) 771 | Dprintf("[%v] \\sum{rtk_i}: %v\n", b.id, total_rtoken) 772 | Dprintf("[%v] T: %v\n", b.id, T) 773 | // TODO: Error Handling 774 | eproof, _ := zksigma.NewEquivalenceProof(ZKLedgerCurve, T, total_rtoken, ZKLedgerCurve.H, b.pki.Get(b.id), b.pki.GetSK(b.id)) 775 | return total_clear, eproof 776 | } 777 | 778 | func (b *Bank) answerClearSum() *big.Int { 779 | total_clear := big.NewInt(0) 780 | if *useCache { 781 | total_clear = b.ValueCache 782 | } else { 783 | for _, v := range b.transactions { 784 | total_clear.Add(total_clear, v.value) 785 | } 786 | } 787 | return total_clear 788 | } 789 | -------------------------------------------------------------------------------- /bank_test.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | "runtime" 7 | "sync" 8 | "testing" 9 | "time" 10 | 11 | "github.com/mit-dci/zksigma" 12 | ) 13 | 14 | func TestSetupBanks(t *testing.T) { 15 | n := 2 16 | pki := &PKI{} 17 | pki.MakeTest(n) 18 | l := MakeLedger(n) 19 | a := MakeAuditor(n, pki) 20 | banks := SetupLocalBanks(n, l, pki) 21 | l.Banks = make([]BankClient, n) 22 | a.banks = make([]BankClient, n) 23 | for i := 0; i < n; i++ { 24 | l.Banks[i] = banks[i] 25 | a.banks[i] = banks[i] 26 | } 27 | if len(l.Banks) != n { 28 | t.Errorf("Incorrect ledger setup: %v banks\n", len(l.Banks)) 29 | } 30 | for i := 0; i < n; i++ { 31 | if banks[i].id != i { 32 | t.Errorf("Bad bank setup %v should be %v\n", banks[i].id, i) 33 | } 34 | } 35 | fmt.Printf("Passed TestSetupBanks\n") 36 | } 37 | 38 | func TestSetupTest(t *testing.T) { 39 | s := SetupTest(2, 0, 500) 40 | defer FinishTest(s) 41 | if len(s.B[0].transactions) != 1 { // my issuance transaction 42 | t.Fatalf("Bank 0 should have 1 issuance transaction; instead has %v\n", len(s.B[0].transactions)) 43 | } 44 | if len(s.B[0].local_ledger.Transactions) != 2 { 45 | s.B[0].DumpLedger(nil, nil) 46 | t.Fatalf("Bank 0 should have 2 in local ledger; instead has %v\n", len(s.B[0].local_ledger.Transactions)) 47 | } 48 | if len(s.B[1].transactions) != 1 { // my issuance transaction 49 | t.Fatalf("Bank 1 should have 1 issuance transaction; instead has %v\n", len(s.B[1].transactions)) 50 | } 51 | if len(s.B[1].local_ledger.Transactions) != 2 { 52 | s.B[1].DumpLedger(nil, nil) 53 | t.Fatalf("Bank 1 should have 2 in local ledger; instead has %v\n", len(s.B[1].local_ledger.Transactions)) 54 | } 55 | time.Sleep(5 * time.Millisecond) 56 | if len(s.A.local_ledger.Transactions) != 2 { 57 | t.Fatalf("Auditor should have 2 in local ledger; instead has %v\n", len(s.A.local_ledger.Transactions)) 58 | } 59 | } 60 | 61 | func TestBanksWithTransaction(t *testing.T) { 62 | s := SetupTest(2, 1, 500) 63 | defer FinishTest(s) 64 | s.B[0].mu.Lock() 65 | defer s.B[0].mu.Unlock() 66 | s.B[1].mu.Lock() 67 | defer s.B[1].mu.Unlock() 68 | s.A.mu.Lock() 69 | defer s.A.mu.Unlock() 70 | 71 | if len(s.B[0].transactions) != 2 { //incorporating the issuance transactions 72 | t.Fatalf("Bank 0 should have 2 transactions; instead has %v\n", len(s.B[0].transactions)) 73 | } 74 | if len(s.B[0].local_ledger.Transactions) != 3 { 75 | s.B[0].DumpLedger(nil, nil) 76 | t.Fatalf("Bank 0 should have 3 in local ledger; instead has %v\n", len(s.B[0].local_ledger.Transactions)) 77 | } 78 | var tx *Transaction 79 | var ok bool 80 | if tx, ok = s.B[0].transactions[2]; !ok { 81 | t.Fatalf("Bank 0 should have index 0 transaction %v\n", s.B[0].transactions) 82 | } 83 | if tx.value.Cmp(big.NewInt(-100)) != 0 { 84 | t.Fatalf("Bank 0 should have one -100 transaction %v\n", s.B[0].transactions[1]) 85 | } 86 | 87 | if len(s.B[1].transactions) != 2 { 88 | s.B[1].print_transactions() 89 | t.Fatalf("Bank 1 should have 2 transactions; instead has %v\n", len(s.B[1].transactions)) 90 | } 91 | if len(s.B[1].local_ledger.Transactions) != 3 { 92 | t.Fatalf("Bank 1 should have 3 in local ledger; instead has %v\n", len(s.B[1].local_ledger.Transactions)) 93 | } 94 | if tx, ok = s.B[1].transactions[2]; !ok { 95 | t.Fatalf("Bank 1 should have index 1 transaction %v\n", s.B[1].transactions) 96 | } 97 | if tx.value.Cmp(big.NewInt(100)) != 0 { 98 | t.Fatalf("Bank 1 should have one 100 transaction %v\n", *s.B[1].transactions[2]) 99 | } 100 | 101 | if len(s.A.local_ledger.Transactions) != 3 { 102 | t.Fatalf("Auditor should have 3 in local ledger; instead has %v\n", len(s.A.local_ledger.Transactions)) 103 | } 104 | 105 | // Test RToken 106 | rt := s.L.Transactions[2].Entries[1].RToken // we did two issuances, so the ledger should have a total of 3 107 | tx, ok = s.B[1].transactions[2] 108 | if !ok { 109 | t.Fatalf("Bank 1 should have index 1 transaction %v\n", s.B[1].transactions) 110 | } 111 | if !zksigma.VerifyR(ZKLedgerCurve, rt, s.B[1].pki.Get(1), tx.r) { 112 | t.Errorf("Bad RToken %v\n", rt) 113 | } else { 114 | fmt.Printf("Passed TestBanksWithTransaction\n") 115 | } 116 | } 117 | 118 | func TestOutOfOrderBanks(t *testing.T) { 119 | s := SetupTest(2, 0, 500) 120 | defer FinishTest(s) 121 | b := s.B[0] 122 | entries := make([]Entry, 2) 123 | for i := 0; i < 2; i++ { 124 | entries[i].CommAux = zksigma.Zero 125 | entries[i].Comm = zksigma.Zero 126 | entries[i].RToken = zksigma.Zero 127 | } 128 | b.Notify(&EncryptedTransaction{Index: 3, skipVerify: true, Entries: entries}, nil) 129 | if b.lastSeen != 1 { // should have only seen issuance 130 | t.Errorf("Bank shouldn't have seen anything yet\n") 131 | } 132 | x, ok := <-b.receivedTxns 133 | if !ok { 134 | t.Errorf("Bank shouldn't have processed this yet, should be something in channel\n") 135 | } 136 | if x.Index != 3 { 137 | t.Errorf("Wrong transaction from channel.\n") 138 | } 139 | b.receivedTxns <- x 140 | if len(b.local_ledger.Transactions) != 2 { 141 | t.Errorf("Bank should not have processed transaction\n") 142 | } 143 | if b.lastSeen != 1 { 144 | t.Errorf("Bank shouldn't have seen anything yet\n") 145 | } 146 | b.Notify(&EncryptedTransaction{Index: 2, skipVerify: true, Entries: entries}, nil) 147 | time.Sleep(10 * time.Millisecond) 148 | if len(b.local_ledger.Transactions) != 4 { 149 | t.Errorf("Bank should have processed both transactions\n") 150 | } 151 | if b.lastSeen != 3 { 152 | t.Errorf("Bank should have seen two transactions %v\n", b.lastSeen) 153 | } else { 154 | fmt.Printf("Passed TestOutOfOrderBanks\n") 155 | } 156 | } 157 | 158 | func TestManyConcurrent(t *testing.T) { 159 | n := 5 160 | s := SetupTest(n, 0, 5000) 161 | defer FinishTest(s) 162 | var wg sync.WaitGroup 163 | for i := 0; i < 5; i++ { 164 | wg.Add(1) 165 | go func(i int) { 166 | s.B[i%n].CreateEncryptedTransaction((i+1)%n, big.NewInt(10)) 167 | wg.Done() 168 | }(i) 169 | wg.Wait() 170 | } 171 | 172 | // Wait for transactions to get sent to everyone 173 | time.Sleep(20 * time.Millisecond) 174 | fmt.Printf("Passed TestManyConcurrent\n") 175 | } 176 | 177 | func TestConcurrentCreate(t *testing.T) { 178 | s := SetupTest(2, 0, 500) 179 | defer FinishTest(s) 180 | var wg sync.WaitGroup 181 | for i := 0; i < 10; i++ { 182 | wg.Add(1) 183 | go func(i int) { 184 | s.B[i%2].CreateEncryptedTransaction((i+1)%2, big.NewInt(10)) 185 | wg.Done() 186 | }(i) 187 | wg.Wait() 188 | } 189 | 190 | StopWhen(s, 11) 191 | Wait(s) 192 | 193 | l := s.L 194 | b0 := s.B[0] 195 | b1 := s.B[1] 196 | if len(l.Transactions) != 12 { 197 | t.Errorf("Ledger doesn't have all transactions %v\n", len(l.Transactions)) 198 | } 199 | if len(b0.transactions) != 11 { 200 | t.Errorf("Bank 0 doesn't have all transactions %v\n", len(b0.transactions)) 201 | } 202 | if len(b1.transactions) != 11 { 203 | t.Errorf("Bank 1 doesn't have all transactions %v\n", len(b1.transactions)) 204 | } 205 | audit_val, x := s.A.computeSum(0) 206 | if x != true { 207 | t.Errorf("Bank 0 didn't verify audit\n") 208 | } 209 | if audit_val.Cmp(big.NewInt(500)) != 0 { 210 | t.Errorf("Wrong audit value for bank 0 %v\n", audit_val) 211 | } 212 | fmt.Printf("Passed TestConcurrentCreate\n") 213 | } 214 | 215 | func TestIssuance(t *testing.T) { 216 | s := SetupTest(2, 0, 50) 217 | defer FinishTest(s) 218 | v := big.NewInt(50) 219 | etx := s.L.Transactions[1] //Issue(v) 220 | if etx.Sender != 1 { 221 | t.Errorf("Wrong bank %v\n", etx.Sender) 222 | } 223 | en := etx.Entries[1] 224 | if en.V.Cmp(v) != 0 { 225 | t.Errorf("Wrong amount %v\n", etx.Sender) 226 | } 227 | x := make([]zksigma.ECPoint, 0) 228 | if !etx.Verify(s.B[0].pki.PK, x, x, "") { // pass in the first banks public keys for now 229 | t.Errorf("Didn't verify %v\n", etx) 230 | } else { 231 | fmt.Printf("Passed TestIssuance\n") 232 | } 233 | } 234 | 235 | func TestWithdrawal(t *testing.T) { 236 | s := SetupTest(2, 0, 500) 237 | defer FinishTest(s) 238 | v := big.NewInt(-50) 239 | etx := s.B[1].Withdraw(v, nil) 240 | if etx.Sender != 1 { 241 | t.Errorf("Wrong bank %v\n", etx.Sender) 242 | } 243 | en := etx.Entries[1] 244 | if en.V.Cmp(v) != 0 { 245 | t.Errorf("Wrong amount %v\n", etx.Sender) 246 | } 247 | x := make([]zksigma.ECPoint, 0) 248 | if !etx.Verify(s.B[0].pki.PK, x, x, "") { 249 | t.Errorf("Didn't verify %v\n", etx) 250 | } else { 251 | fmt.Printf("Passed TestWithdraw\n") 252 | } 253 | } 254 | 255 | func TestVerifyTxn(t *testing.T) { 256 | bnum := 10 257 | s := SetupTest(bnum, 0, 1000) 258 | defer FinishTest(s) 259 | 260 | // Need a copy of these because CreateEncryptedTransaction will 261 | // send it to the ledger, which will cause each bank to process 262 | // it, updating intermediate datastructures and no longer making 263 | // it valid. 264 | commsCache := make([]zksigma.ECPoint, bnum) 265 | rtokenCache := make([]zksigma.ECPoint, bnum) 266 | for i := 0; i < bnum; i++ { 267 | commsCache[i] = zksigma.ECPoint{big.NewInt(0).Set(s.B[0].CommsCache[i].X), big.NewInt(0).Set(s.B[0].CommsCache[i].Y)} 268 | rtokenCache[i] = zksigma.ECPoint{big.NewInt(0).Set(s.B[0].RTokenCache[i].X), big.NewInt(0).Set(s.B[0].RTokenCache[i].Y)} 269 | } 270 | etx := s.B[0].CreateEncryptedTransaction(1, big.NewInt(1)) 271 | v := etx.Verify(s.B[0].pki.PK, commsCache, rtokenCache, "") 272 | if !v { 273 | t.Errorf("Could not verify txn\n") 274 | } else { 275 | fmt.Printf("Passed TestVerifyTxn\n") 276 | } 277 | } 278 | 279 | func BenchmarkAuditOneBank(b *testing.B) { 280 | s := SetupTest(2, 1000, 500) 281 | defer FinishTest(s) 282 | b.ResetTimer() 283 | for i := 0; i < b.N; i++ { 284 | s.B[0].answerSum() 285 | } 286 | } 287 | 288 | func BenchmarkVerifyTwoBanks(b *testing.B) { benchmarkVerify(2, b) } 289 | func BenchmarkVerifyFourBanks(b *testing.B) { benchmarkVerify(4, b) } 290 | func BenchmarkVerifySixBanks(b *testing.B) { benchmarkVerify(6, b) } 291 | func BenchmarkVerifyEightBanks(b *testing.B) { benchmarkVerify(8, b) } 292 | func BenchmarkVerifyTenBanks(b *testing.B) { benchmarkVerify(10, b) } 293 | func BenchmarkVerifyTwelveBanks(b *testing.B) { benchmarkVerify(12, b) } 294 | func BenchmarkVerifyFourteenBanks(b *testing.B) { benchmarkVerify(14, b) } 295 | func BenchmarkVerifySixteenBanks(b *testing.B) { benchmarkVerify(16, b) } 296 | func BenchmarkVerifyEighteenBanks(b *testing.B) { benchmarkVerify(18, b) } 297 | func BenchmarkVerifyTwentyBanks(b *testing.B) { benchmarkVerify(20, b) } 298 | func BenchmarkVerifyTwentyFourBanks(b *testing.B) { benchmarkVerify(24, b) } 299 | func BenchmarkVerifyThirtyBanks(b *testing.B) { benchmarkVerify(30, b) } 300 | 301 | func benchmarkVerify(bnum int, b *testing.B) { 302 | s := SetupTest(bnum, 0, 1000) 303 | defer FinishTest(s) 304 | pk := s.B[0].pki.PK 305 | 306 | // Need a copy of these because CreateEncryptedTransaction will 307 | // send it to the ledger, which will cause each bank to process 308 | // it, updating intermediate datastructures and no longer making 309 | // it valid. 310 | commsCache := make([]zksigma.ECPoint, bnum) 311 | rtokenCache := make([]zksigma.ECPoint, bnum) 312 | for i := 0; i < bnum; i++ { 313 | commsCache[i] = zksigma.ECPoint{big.NewInt(0).Set(s.B[0].CommsCache[i].X), big.NewInt(0).Set(s.B[0].CommsCache[i].Y)} 314 | rtokenCache[i] = zksigma.ECPoint{big.NewInt(0).Set(s.B[0].RTokenCache[i].X), big.NewInt(0).Set(s.B[0].RTokenCache[i].Y)} 315 | } 316 | etx := s.B[0].CreateEncryptedTransaction(1, big.NewInt(1)) 317 | b.ResetTimer() 318 | for i := 0; i < b.N; i++ { 319 | v := etx.Verify(pk, commsCache, rtokenCache, "") 320 | if !v { 321 | panic("did not verify") 322 | } 323 | } 324 | b.StopTimer() 325 | } 326 | 327 | func BenchmarkCreateTxnTwoBanks(b *testing.B) { benchmarkCreateTxn(2, b) } 328 | func BenchmarkCreateTxnFourBanks(b *testing.B) { benchmarkCreateTxn(4, b) } 329 | func BenchmarkCreateTxnSixBanks(b *testing.B) { benchmarkCreateTxn(6, b) } 330 | func BenchmarkCreateTxnEightBanks(b *testing.B) { benchmarkCreateTxn(8, b) } 331 | func BenchmarkCreateTxnTenBanks(b *testing.B) { benchmarkCreateTxn(10, b) } 332 | func BenchmarkCreateTxnTwelveBanks(b *testing.B) { benchmarkCreateTxn(12, b) } 333 | func BenchmarkCreateTxnFourteenBanks(b *testing.B) { benchmarkCreateTxn(14, b) } 334 | func BenchmarkCreateTxnSixteenBanks(b *testing.B) { benchmarkCreateTxn(16, b) } 335 | func BenchmarkCreateTxnEighteenBanks(b *testing.B) { benchmarkCreateTxn(18, b) } 336 | func BenchmarkCreateTxnTwentyBanks(b *testing.B) { benchmarkCreateTxn(20, b) } 337 | 338 | func benchmarkCreateTxn(bnum int, b *testing.B) { 339 | s := SetupTest(bnum, 0, 1000) 340 | defer FinishTest(s) 341 | StopWhen(s, b.N+bnum) 342 | s.B[0].Issue(big.NewInt(int64(2*b.N)), nil) 343 | b.ResetTimer() 344 | for i := 0; i < b.N; i++ { 345 | s.B[0].CreateEncryptedTransaction(1, big.NewInt(1)) 346 | } 347 | Wait(s) 348 | b.StopTimer() 349 | } 350 | 351 | func xxTestMemUsage(t *testing.T) { 352 | bnum := 10 353 | pki := &PKI{} 354 | pki.MakeTest(bnum) 355 | banks := SetupLocalBanks(bnum, nil, pki) 356 | time.Sleep(20 * time.Millisecond) 357 | var mem runtime.MemStats 358 | runtime.ReadMemStats(&mem) 359 | for j := 0; j < 100; j++ { 360 | etx := &EncryptedTransaction{} 361 | if *rpOutside { 362 | generateRangeProofs(bnum, etx, 1, 0, big.NewInt(1)) 363 | } 364 | banks[0].createLocal(etx, 1, big.NewInt(1)) 365 | } 366 | var mem2 runtime.MemStats 367 | runtime.ReadMemStats(&mem2) 368 | fmt.Printf("%v banks: alloc %v, total alloc %v, heap alloc %v, heap sys %v\n", bnum, mem2.Alloc-mem.Alloc, mem2.TotalAlloc-mem.TotalAlloc, mem2.HeapAlloc-mem.HeapAlloc, mem2.HeapSys-mem.HeapSys) 369 | } 370 | 371 | func BenchmarkCreateLocalTxnTwoBanks(b *testing.B) { benchmarkCreateLocalTxn(2, b) } 372 | func BenchmarkCreateLocalTxnFourBanks(b *testing.B) { benchmarkCreateLocalTxn(4, b) } 373 | func BenchmarkCreateLocalTxnSixBanks(b *testing.B) { benchmarkCreateLocalTxn(6, b) } 374 | func BenchmarkCreateLocalTxnEightBanks(b *testing.B) { benchmarkCreateLocalTxn(8, b) } 375 | func BenchmarkCreateLocalTxnTenBanks(b *testing.B) { benchmarkCreateLocalTxn(10, b) } 376 | func BenchmarkCreateLocalTxnTwelveBanks(b *testing.B) { benchmarkCreateLocalTxn(12, b) } 377 | func BenchmarkCreateLocalTxnFourteenBanks(b *testing.B) { benchmarkCreateLocalTxn(14, b) } 378 | func BenchmarkCreateLocalTxnSixteenBanks(b *testing.B) { benchmarkCreateLocalTxn(16, b) } 379 | func BenchmarkCreateLocalTxnEighteenBanks(b *testing.B) { benchmarkCreateLocalTxn(18, b) } 380 | func BenchmarkCreateLocalTxnTwentyBanks(b *testing.B) { benchmarkCreateLocalTxn(20, b) } 381 | func BenchmarkCreateLocalTxnTwentyFourBanks(b *testing.B) { benchmarkCreateLocalTxn(24, b) } 382 | func BenchmarkCreateLocalTxnThirtyBanks(b *testing.B) { benchmarkCreateLocalTxn(30, b) } 383 | 384 | func benchmarkCreateLocalTxn(bnum int, b *testing.B) { 385 | pki := &PKI{} 386 | pki.MakeTest(bnum) 387 | banks := SetupLocalBanks(bnum, nil, pki) 388 | banks[0].ValueCache.Add(banks[0].ValueCache, big.NewInt(int64(2*b.N))) 389 | b.ResetTimer() 390 | etx := &EncryptedTransaction{} 391 | for i := 0; i < b.N; i++ { 392 | if *rpOutside { 393 | generateRangeProofs(bnum, etx, 1, 0, big.NewInt(1)) 394 | } 395 | banks[0].createLocal(etx, 1, big.NewInt(1)) 396 | } 397 | } 398 | 399 | func BenchmarkUpdateCommCache(b *testing.B) { 400 | value := new(big.Int).SetInt64(50) 401 | // TODO: Error handling 402 | comm, _, _ := zksigma.PedCommit(ZKLedgerCurve, value) 403 | b.ResetTimer() 404 | for n := 0; n < b.N; n++ { 405 | comm = ZKLedgerCurve.Add(comm, comm) 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /clients.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "math/big" 7 | "net/rpc" 8 | "time" 9 | ) 10 | 11 | type APLClientConfig struct { 12 | Hostname string 13 | BasePort int 14 | BankHostnames []string 15 | LedgerHostname string 16 | AuditorHostname string 17 | } 18 | 19 | type BankClient interface { 20 | Audit(a *struct{}, rep *AuditRep) error 21 | Store(req *StoreArgs, _ *struct{}) error 22 | CreateEncryptedTransaction(bank_j int, value *big.Int) *EncryptedTransaction 23 | Notify(etx *EncryptedTransaction, _ *struct{}) error 24 | } 25 | 26 | type RemoteBankClient struct { 27 | client *rpc.Client 28 | } 29 | 30 | func MakeRemoteBankClient() *RemoteBankClient { 31 | bc := &RemoteBankClient{} 32 | return bc 33 | } 34 | 35 | func (bc *RemoteBankClient) connect(hostname string, port int) { 36 | for done := false; !done; { 37 | c, err := rpc.Dial("tcp", fmt.Sprintf("%s:%d", hostname, port)) 38 | if err == nil { 39 | bc.client = c 40 | done = true 41 | } else { 42 | Dprintf("Couldn't connect to bank %v:%v, %v looping\n", hostname, port, err) 43 | time.Sleep(1 * time.Second) 44 | } 45 | } 46 | } 47 | 48 | func (bc *RemoteBankClient) Notify(etx *EncryptedTransaction, _ *struct{}) error { 49 | return bc.client.Call("Bank.Notify", etx, nil) 50 | } 51 | 52 | func (bc *RemoteBankClient) Audit(a *struct{}, rep *AuditRep) error { 53 | return bc.client.Call("Bank.Audit", a, rep) 54 | } 55 | 56 | func (bc *RemoteBankClient) Store(req *StoreArgs, _ *struct{}) error { 57 | return bc.client.Call("Bank.Store", req, nil) 58 | } 59 | 60 | func (bc *RemoteBankClient) CreateEncryptedTransaction(bank_j int, value *big.Int) *EncryptedTransaction { 61 | log.Fatalf("remote create not implemented yet") 62 | return nil 63 | } 64 | 65 | type AuditorClient interface { 66 | Notify(etx *EncryptedTransaction, _ *struct{}) error 67 | } 68 | 69 | type LedgerClient interface { 70 | StartTxn(bank_i int, idx *int) error 71 | AppendTxn(etx *EncryptedTransaction, _ *struct{}) error 72 | } 73 | 74 | type IssuerClient interface { 75 | Issue(value *big.Int, targetBank *int) error 76 | } 77 | 78 | type RemoteLedgerClient struct { 79 | client *rpc.Client 80 | } 81 | 82 | func MakeRemoteLedgerClient() *RemoteLedgerClient { 83 | lc := &RemoteLedgerClient{} 84 | lc.client = nil 85 | return lc 86 | } 87 | 88 | func (lc *RemoteLedgerClient) Connect(hostname string, port int) { 89 | for done := false; !done; { 90 | c, err := rpc.Dial("tcp", fmt.Sprintf("%s:%d", hostname, port)) 91 | if err == nil { 92 | Dprintf("Connected to ledger %v:%v %v\n", hostname, port, err) 93 | lc.client = c 94 | done = true 95 | } else { 96 | Dprintf("Couldn't connect to ledger %v:%v %v, looping\n", hostname, port, err) 97 | time.Sleep(1 * time.Second) 98 | } 99 | } 100 | } 101 | 102 | func (lc *RemoteLedgerClient) StartTxn(bank_i int, idx *int) error { 103 | err := lc.client.Call("Ledger.StartTxn", bank_i, idx) 104 | if err != nil { 105 | Dprintf("StartTxn call to ledger from bank %v failed\n", bank_i) 106 | fmt.Println(err) 107 | } 108 | return err 109 | } 110 | 111 | func (lc *RemoteLedgerClient) AppendTxn(etx *EncryptedTransaction, _ *struct{}) error { 112 | err := lc.client.Call("Ledger.AppendTxn", etx, nil) 113 | if err != nil { 114 | Dprintf("AppendTxn call to ledger for tx %v failed\n", etx.Index) 115 | fmt.Println(err) 116 | } 117 | return err 118 | } 119 | 120 | type RemoteAuditorClient struct { 121 | client *rpc.Client 122 | } 123 | 124 | func MakeRemoteAuditorClient() *RemoteAuditorClient { 125 | ac := &RemoteAuditorClient{} 126 | return ac 127 | } 128 | 129 | func (ac *RemoteAuditorClient) connect(hostname string, port int) { 130 | for done := false; !done; { 131 | c, err := rpc.Dial("tcp", fmt.Sprintf("%s:%d", hostname, port)) 132 | if err == nil { 133 | ac.client = c 134 | done = true 135 | } else { 136 | Dprintf("Couldn't connect to auditor %v:%v, looping\n", hostname, port) 137 | time.Sleep(1 * time.Second) 138 | } 139 | } 140 | } 141 | 142 | func (ac *RemoteAuditorClient) Notify(etx *EncryptedTransaction, _ *struct{}) error { 143 | return ac.client.Call("Auditor.Notify", etx, nil) 144 | } 145 | -------------------------------------------------------------------------------- /cmd/apl-auditor/auditor.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "math" 7 | 8 | "bufio" 9 | "bytes" 10 | "encoding/json" 11 | "errors" 12 | "io/ioutil" 13 | "log" 14 | "os" 15 | "path/filepath" 16 | "strings" 17 | "time" 18 | 19 | "github.com/mit-dci/zkledger" 20 | ) 21 | 22 | ///////// PARAMETERS 23 | var numBanks = flag.Int("num", 2, "num banks") 24 | var basePort = flag.Int("port", 7000, "Base port") 25 | var testID = flag.String("testID", "0", "Unique identifier for this test") 26 | var testName = flag.String("t", "h", "Audit protocol to run for test:\n h : Herfindahl Index\n s : private sum") 27 | var remote = flag.Bool("r", false, "[Testing Only] Is this a remote connection?") 28 | var plannedtxn = flag.Int("ntxn", 5, "number of transactions to do") 29 | 30 | type hostnames []string 31 | 32 | var bankHostnames hostnames 33 | 34 | func (h *hostnames) String() string { 35 | return fmt.Sprint(*h) 36 | } 37 | 38 | func (h *hostnames) Set(value string) error { 39 | if len(*h) > 0 { 40 | return errors.New("hostnames flag already set") 41 | } 42 | for _, host := range strings.Split(value, ",") { 43 | *h = append(*h, host) 44 | } 45 | return nil 46 | } 47 | 48 | func init() { 49 | flag.Var(&bankHostnames, "bh", "comma separated list of hostnames of the banks") 50 | } 51 | 52 | //////////////////// 53 | 54 | //////// HELPER FUNCS 55 | func check(e error) { 56 | if e != nil { 57 | panic(e) 58 | } 59 | } 60 | 61 | // exists returns whether the given file or directory exists or not 62 | func exists(path string) (bool, error) { 63 | _, err := os.Stat(path) 64 | if err == nil { 65 | return true, nil 66 | } 67 | if os.IsNotExist(err) { 68 | return false, nil 69 | } 70 | return true, err 71 | } 72 | 73 | //////////////////// 74 | 75 | type Performance struct { 76 | TotalTime time.Duration // in nanoseconds 77 | NTXN int 78 | Throughput float64 79 | Latency float64 80 | } 81 | 82 | func SavePerformanceResults(p Performance) { 83 | filename := "auditor_performance_ntxn_" + fmt.Sprintf("%d", p.NTXN) + "_" + fmt.Sprintf("%d", time.Now().UnixNano()) + "_testID_" + *testID + ".log" 84 | fmt.Printf("[A] Dumping results to %s\n", filename) 85 | 86 | cwd, err := filepath.Abs(filepath.Dir(os.Args[0])) 87 | check(err) 88 | testDirectory := filepath.Join(cwd, *testID) 89 | testDirExists, err2 := exists(testDirectory) 90 | check(err2) 91 | 92 | if !testDirExists { 93 | os.Mkdir(testDirectory, 0777) 94 | } 95 | 96 | fullPathFilename := filepath.Join(testDirectory, filename) 97 | 98 | var buf bytes.Buffer 99 | enc := json.NewEncoder(&buf) 100 | enc.Encode(p) 101 | err = ioutil.WriteFile(fullPathFilename, buf.Bytes(), 0666) 102 | check(err) 103 | } 104 | 105 | func main() { 106 | flag.Parse() 107 | if len(bankHostnames) != *numBanks { 108 | fmt.Println("Auditor", len(bankHostnames), *numBanks) 109 | log.Fatal("Auditor: Hostnames given should have same length as number of banks") 110 | } 111 | 112 | pki := &zkledger.PKI{} 113 | pki.MakeTestWithKeys(*numBanks) 114 | auditor := zkledger.MakeAuditor(*numBanks, pki) 115 | go func() { 116 | <-auditor.Setup 117 | // if we're remote then we're doing big transactions and need to know when to audit 118 | // since our big transactions do ntxn*numbanks + numbanks we can check to see if we 119 | // have this many txns. When that is the case then we can assume to be ready to audit 120 | if *remote { 121 | maxTXCount := *plannedtxn**numBanks + *numBanks 122 | curTXCount := auditor.GetNumTX(nil, nil) 123 | for curTXCount < maxTXCount { // once this condition is no longer satisified we can run 124 | // down to audit 125 | time.Sleep(time.Second * 10) // check every ten seconds if we're done or not 126 | curTXCount = auditor.GetNumTX(nil, nil) 127 | } 128 | } else { 129 | reader := bufio.NewReader(os.Stdin) 130 | //fmt.Println(">") 131 | reader.ReadString('\n') 132 | } 133 | // begin audit 134 | // val := nil 135 | var val string 136 | var start time.Time 137 | var end time.Duration 138 | var total time.Duration 139 | var avg time.Duration 140 | times := make([]time.Duration, 20) 141 | if *testName == "h" { 142 | for i := 0; i < 20; i++ { 143 | start = time.Now() 144 | // TODO: Error handling 145 | x, _ := auditor.Herfindahl(true, nil) 146 | times[i] = time.Since(start) 147 | total += times[i] 148 | val = x.String() 149 | //fmt.Printf("Audit tm %v: %v\n", i, times[i]) 150 | time.Sleep(1 * time.Millisecond) 151 | } 152 | avg = total / time.Duration(len(times)) 153 | fmt.Printf("Audit tm withcache avg: %v\n", avg) 154 | var variance int64 155 | for i := 0; i < len(times); i++ { 156 | variance = variance + int64(math.Pow(float64((times[i]-avg)), 2)) 157 | } 158 | variance = variance / int64(len(times)) 159 | stddev := int64(math.Sqrt(float64(variance))) 160 | stderr := stddev / int64(math.Sqrt(float64(len(times)))) 161 | fmt.Printf("Audit tm withcache stddev: %v\n", time.Duration(stddev)) 162 | fmt.Printf("Audit tm withcache stderr: %v\n", time.Duration(stderr)) 163 | } else { 164 | start = time.Now() 165 | x := auditor.Audit(nil, nil) 166 | end = time.Since(start) 167 | val = x.String() 168 | } 169 | // end audit 170 | 171 | ntxn := auditor.GetNumTX(nil, nil) 172 | 173 | p := Performance{ 174 | TotalTime: end, 175 | NTXN: ntxn, 176 | Throughput: 0, 177 | Latency: avg.Seconds(), 178 | } 179 | SavePerformanceResults(p) 180 | 181 | fmt.Println("audit:", val) 182 | fmt.Println("Auditing time: ", avg) 183 | 184 | total = 0 185 | for i := 0; i < 20; i++ { 186 | start = time.Now() 187 | // TODO: Error handling 188 | x, _ := auditor.Herfindahl(false, nil) 189 | times[i] = time.Since(start) 190 | total += times[i] 191 | val = x.String() 192 | if i == 0 { 193 | fmt.Printf("Audit tm nocache %v: %v\n", i, times[i]) 194 | } 195 | time.Sleep(1 * time.Millisecond) 196 | } 197 | avg = total / time.Duration(len(times)) 198 | fmt.Printf("Audit tm nocache avg: %v\n", avg) 199 | var variance int64 200 | for i := 0; i < len(times); i++ { 201 | variance = variance + int64(math.Pow(float64((times[i]-avg)), 2)) 202 | } 203 | variance = variance / int64(len(times)) 204 | stddev := int64(math.Sqrt(float64(variance))) 205 | stderr := stddev / int64(math.Sqrt(float64(len(times)))) 206 | fmt.Printf("Audit tm nocache stddev: %v\n", time.Duration(stddev)) 207 | fmt.Printf("Audit tm nocache stderr: %v\n", time.Duration(stderr)) 208 | fmt.Println("done") 209 | }() 210 | zkledger := zkledger.APLClientConfig{ 211 | Hostname: "localhost", 212 | BasePort: *basePort, 213 | BankHostnames: bankHostnames, 214 | LedgerHostname: "", 215 | AuditorHostname: "localhost", 216 | } 217 | auditor.Go(zkledger, nil) 218 | } 219 | -------------------------------------------------------------------------------- /cmd/apl-bank/bank.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "math/big" 8 | "time" 9 | 10 | "bytes" 11 | "encoding/json" 12 | "errors" 13 | "io/ioutil" 14 | "os" 15 | "path/filepath" 16 | "strconv" 17 | "strings" 18 | 19 | "github.com/mit-dci/zkledger" 20 | ) 21 | 22 | ///////// PARAMETERS 23 | var numBanks = flag.Int("num", 2, "num banks") 24 | var curBankID = flag.Int("id", 0, "Bank id") 25 | var basePort = flag.Int("port", 7000, "Base port") 26 | var hostname = flag.String("hostname", "localhost", "host") 27 | var ledgerHostname = flag.String("lh", "localhost", "ledger hostname") 28 | var ntxn = flag.Int("ntxn", 5, "number of transactions") 29 | var testToRun = flag.String("t", "small", "Available tests: big,small") 30 | var testID = flag.String("testID", "0", "Unique identifier for this test") 31 | var noTX = flag.Bool("noTX", false, "Set to true if bank will not transact") 32 | var dumpLedger = flag.Bool("dump", false, "Dump ledger") 33 | var pinterval = flag.Int("pinterval", 60, "How many seconds to print progress") 34 | 35 | type hostnames []string 36 | 37 | var bankHostnames hostnames 38 | 39 | func (h *hostnames) String() string { 40 | return fmt.Sprint(*h) 41 | } 42 | 43 | func (h *hostnames) Set(value string) error { 44 | if len(*h) > 0 { 45 | return errors.New("hostnames flag already set") 46 | } 47 | for _, host := range strings.Split(value, ",") { 48 | *h = append(*h, host) 49 | } 50 | return nil 51 | } 52 | 53 | func init() { 54 | flag.Var(&bankHostnames, "bh", "comma separated list of hostnames of the banks") 55 | } 56 | 57 | //////////////////// 58 | 59 | /////// HELPER FUNCS 60 | func check(e error) { 61 | if e != nil { 62 | panic(e) 63 | } 64 | } 65 | 66 | // exists returns whether the given file or directory exists or not 67 | func exists(path string) (bool, error) { 68 | _, err := os.Stat(path) 69 | if err == nil { 70 | return true, nil 71 | } 72 | if os.IsNotExist(err) { 73 | return false, nil 74 | } 75 | return true, err 76 | } 77 | 78 | //////////////////// 79 | 80 | type Performance struct { 81 | TotalTime time.Duration // in nanoseconds 82 | NTXN int 83 | Throughput float64 84 | Latency float64 85 | } 86 | 87 | func SavePerformanceResults(p Performance) { 88 | filename := "bank_" + strconv.Itoa(*curBankID) + "_performance_ntxn_" + fmt.Sprintf("%d", p.NTXN) + "_" + fmt.Sprintf("%d", time.Now().UnixNano()) + "_testID_" + *testID + ".log" 89 | fmt.Printf("[%v] Dumping results to %s\n", *curBankID, filename) 90 | 91 | cwd, err := filepath.Abs(filepath.Dir(os.Args[0])) 92 | check(err) 93 | testDirectory := filepath.Join(cwd, *testID) 94 | testDirExists, err2 := exists(testDirectory) 95 | check(err2) 96 | 97 | if !testDirExists { 98 | os.Mkdir(testDirectory, 0777) 99 | } 100 | 101 | fullPathFilename := filepath.Join(testDirectory, filename) 102 | 103 | var buf bytes.Buffer 104 | enc := json.NewEncoder(&buf) 105 | enc.Encode(p) 106 | err = ioutil.WriteFile(fullPathFilename, buf.Bytes(), 0666) 107 | check(err) 108 | } 109 | 110 | func main() { 111 | flag.Parse() 112 | if len(bankHostnames) != *numBanks { 113 | fmt.Printf("[%v] hostnames %v\n", *curBankID, bankHostnames) 114 | log.Fatal("Bank: Hostnames given should have same length as number of banks") 115 | 116 | } 117 | pki := &zkledger.PKI{} 118 | pki.MakeTestWithKeys(*numBanks) 119 | bank := zkledger.MakeBank(*curBankID, *numBanks, nil, pki) 120 | if !(*noTX) { 121 | fmt.Printf("[%v] Running test %v\n", *curBankID, *testToRun) 122 | if *testToRun == "small" { 123 | go small_test(bank) 124 | } else if *testToRun == "big" { 125 | go big_test(bank) 126 | } else { 127 | go big_test(bank) 128 | } 129 | } else { 130 | fmt.Printf("[%v] Not running anything because noTX is set to %v\n", *curBankID, *noTX) 131 | } 132 | zkledger := zkledger.APLClientConfig{ 133 | Hostname: *hostname, 134 | BasePort: *basePort, 135 | BankHostnames: bankHostnames, 136 | LedgerHostname: *ledgerHostname, 137 | AuditorHostname: "", 138 | } 139 | _ = zkledger 140 | bank.Go(zkledger, nil) 141 | } 142 | 143 | func small_test(bank *zkledger.Bank) { 144 | <-bank.Setup 145 | start := time.Now() 146 | maxIdx := 0 147 | 148 | if *curBankID == 0 { 149 | v := big.NewInt(10) 150 | bank.Issue(v, nil) // txn 0 151 | bank.CreateEncryptedTransaction(1, v) // txn 1 sending 10 from b0 to b1 152 | } else { 153 | time.Sleep(1 * time.Second) 154 | v := big.NewInt(5) 155 | bank.CreateEncryptedTransaction(0, v) // txn 2 sending 5 from b1 to b0 156 | } 157 | 158 | c, ok := bank.Inflight[maxIdx] 159 | if !ok { 160 | log.Fatal("hmmm") 161 | } 162 | <-c 163 | end := time.Since(start) 164 | 165 | p := Performance{ 166 | Throughput: float64(*ntxn) / float64(end.Seconds()), 167 | Latency: end.Seconds() / float64(*ntxn), 168 | } 169 | 170 | fmt.Printf("[%v] Number per second: %v\n", *curBankID, p.Throughput) 171 | fmt.Printf("[%v] Latency: %vs\n", *curBankID, p.Latency) 172 | 173 | SavePerformanceResults(p) 174 | 175 | if *dumpLedger { 176 | bank.DumpLedger(nil, nil) 177 | } 178 | fmt.Printf("done\n") 179 | 180 | } 181 | 182 | func big_test(bank *zkledger.Bank) { 183 | <-bank.Setup 184 | v := big.NewInt(1000000) 185 | bank.Issue(v, nil) // txn 0 186 | receiver := (*curBankID + 1) % *numBanks 187 | v = big.NewInt(int64(*curBankID) + 1) 188 | start := time.Now() 189 | interval := time.Now() 190 | maxIdx := 0 191 | for i := 0; i < *ntxn; i++ { 192 | etx := bank.CreateEncryptedTransaction(receiver, v) 193 | if etx.Index > maxIdx { 194 | maxIdx = etx.Index 195 | } 196 | if time.Since(interval) > time.Duration(*pinterval)*time.Second { 197 | fmt.Printf("[%v] %v / %v\n", *curBankID, i, *ntxn) 198 | interval = time.Now() 199 | } 200 | } 201 | c, ok := bank.Inflight[maxIdx] 202 | if !ok { 203 | log.Fatal("hmmm") 204 | } 205 | <-c 206 | end := time.Since(start) 207 | 208 | p := Performance{ 209 | TotalTime: end, 210 | NTXN: *ntxn, 211 | Throughput: float64(*ntxn) / float64(end.Seconds()), 212 | Latency: end.Seconds() / float64(*ntxn), 213 | } 214 | 215 | fmt.Printf("[%v] Transactions per second: %v\n", *curBankID, p.Throughput) 216 | fmt.Printf("[%v] Latency per txn: %vs\n", *curBankID, p.Latency) 217 | 218 | SavePerformanceResults(p) 219 | 220 | if *dumpLedger { 221 | bank.DumpLedger(nil, nil) 222 | } 223 | fmt.Printf("done\n") 224 | } 225 | -------------------------------------------------------------------------------- /cmd/apl-ledger/ledger.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "errors" 7 | "fmt" 8 | "log" 9 | "strings" 10 | 11 | "github.com/mit-dci/zkledger" 12 | ) 13 | 14 | var num = flag.Int("num", 2, "num banks") 15 | var basePort = flag.Int("port", 7000, "Base port") 16 | var auditorHostname = flag.String("ah", "localhost", "auditor hostname") 17 | 18 | type hostnames []string 19 | 20 | var bankHostnames hostnames 21 | 22 | func (h *hostnames) String() string { 23 | return fmt.Sprint(*h) 24 | } 25 | 26 | func (h *hostnames) Set(value string) error { 27 | if len(*h) > 0 { 28 | return errors.New("hostnames flag already set") 29 | } 30 | for _, host := range strings.Split(value, ",") { 31 | *h = append(*h, host) 32 | } 33 | return nil 34 | } 35 | 36 | func init() { 37 | flag.Var(&bankHostnames, "bh", "comma separated list of hostnames of the banks") 38 | } 39 | 40 | func main() { 41 | flag.Parse() 42 | if len(bankHostnames) != *num { 43 | fmt.Println("Ledger", len(bankHostnames), *num) 44 | log.Fatal("Ledger: Hostnames given should have same length as number of banks") 45 | } 46 | ledger := zkledger.MakeLedger(*num) 47 | zkledger := zkledger.APLClientConfig{ 48 | Hostname: "", 49 | BasePort: *basePort, 50 | BankHostnames: bankHostnames, 51 | LedgerHostname: "", 52 | AuditorHostname: *auditorHostname, 53 | } 54 | ledger.Go(zkledger, nil) 55 | } 56 | -------------------------------------------------------------------------------- /cmd/keygen/keygen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | 6 | "fmt" 7 | 8 | "github.com/mit-dci/zkledger" 9 | ) 10 | 11 | var num = flag.Int("num", 2, "The number of banks you want generate keys for") 12 | var loadKeys = flag.Bool("load", false, "Loads the keys if they already exist") 13 | 14 | func main() { 15 | flag.Parse() 16 | pki := zkledger.PKI{} 17 | if *loadKeys { 18 | pki.MakeTestWithKeys(*num) 19 | } else { 20 | pki.MakeTest(*num) 21 | } 22 | 23 | fmt.Println(pki) 24 | } 25 | -------------------------------------------------------------------------------- /cmd/setup/.gitignore: -------------------------------------------------------------------------------- 1 | apl-bank 2 | apl-ledger 3 | apl-auditor 4 | main 5 | .ipynb_checkpoints 6 | setup 7 | *.log 8 | alternateBanks*/ 9 | basic*/ 10 | 1kTX*/ 11 | 500TX*/ 12 | one_tx.txt -------------------------------------------------------------------------------- /cmd/setup/apl_env.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "fmt" 6 | "io" 7 | "log" 8 | "os" 9 | "os/exec" 10 | "strconv" 11 | "strings" 12 | "sync" 13 | "time" 14 | ) 15 | 16 | type APLEnvironment struct { 17 | Ledger *exec.Cmd 18 | Auditor *exec.Cmd 19 | Banks []*exec.Cmd 20 | 21 | LedgerReadPipe io.ReadCloser 22 | AuditorReadPipe io.ReadCloser 23 | BankReadPipes []io.ReadCloser 24 | 25 | AuditorWritePipe io.WriteCloser 26 | 27 | bankTally chan int 28 | auditorStatus chan bool 29 | 30 | throughput []float64 31 | latency []time.Duration 32 | auditing time.Duration 33 | stddev time.Duration 34 | stderr time.Duration 35 | remote bool 36 | ac *APLConfig 37 | } 38 | 39 | func (ae *APLEnvironment) init(numBanks int, remote bool, ac *APLConfig) { 40 | ae.Banks = make([]*exec.Cmd, numBanks) 41 | ae.BankReadPipes = make([]io.ReadCloser, numBanks) 42 | ae.bankTally = make(chan int) 43 | ae.auditorStatus = make(chan bool) 44 | ae.throughput = make([]float64, numBanks) 45 | ae.latency = make([]time.Duration, numBanks) 46 | ae.remote = remote 47 | ae.ac = ac 48 | } 49 | 50 | func (ae *APLEnvironment) shutdown() { 51 | if ae.remote { 52 | ae.shutdown_remote() 53 | } else { 54 | ae.shutdown_local() 55 | } 56 | } 57 | 58 | func (ae *APLEnvironment) start(ntxn int, testID string, numBanksTransacting int, auditFunction string) { 59 | if ae.remote { 60 | ae.start_remote(ntxn, testID, numBanksTransacting, auditFunction) 61 | } else { 62 | ae.start_local(ntxn, testID, numBanksTransacting, auditFunction) 63 | } 64 | } 65 | 66 | func (ae *APLEnvironment) shutdown_local() { 67 | // kill the ledger 68 | pkill := true 69 | if err := ae.Ledger.Process.Kill(); err != nil { 70 | fmt.Printf("failed to kill ledger: %v", err) 71 | pkill = true 72 | } 73 | 74 | // kill the auditor 75 | if err := ae.Auditor.Process.Kill(); err != nil { 76 | fmt.Printf("failed to kill ledger: %v", err) 77 | pkill = true 78 | } 79 | 80 | // kill the banks 81 | for i := 0; i < len(ae.Banks); i++ { 82 | if err := ae.Banks[i].Process.Kill(); err != nil { 83 | fmt.Printf("failed to kill bank %v: %v", i, err) 84 | pkill = true 85 | } 86 | } 87 | if pkill { 88 | if err := exec.Command("pkill", "apl").Run(); err != nil { 89 | log.Fatalf("Fail pkill failed: %v", err) 90 | } 91 | } 92 | return 93 | } 94 | 95 | func (ae *APLEnvironment) shutdown_remote() { 96 | // kill the ledger 97 | err := ae.Ledger.Process.Kill() 98 | check(err, "failed to kill:", err) 99 | 100 | // kill the auditor 101 | err = ae.Auditor.Process.Kill() 102 | check(err, "failed to kill:", err) 103 | 104 | // kill the banks 105 | for i := 0; i < len(ae.Banks); i++ { 106 | cmd := ae.Banks[i] 107 | if err := cmd.Process.Kill(); err != nil { 108 | log.Fatal("failed to kill: ", err) 109 | } 110 | } 111 | 112 | // Double tap and directly demand the death of remote apl instances 113 | // we need this in order to make sure that the items are executable 114 | 115 | killstring := "kill $(ps aux | grep apl | awk '{ print $2}' | awk '{print $1}')" 116 | //killstring := "ps aux | grep apl" 117 | log.Println("> killing ledger") 118 | // ledger 119 | hst0Connect := ae.ac.ledgerHostname 120 | if *user != "" { 121 | hst0Connect = *user + "@" + ae.ac.ledgerHostname 122 | } 123 | cmd := exec.Command(sshName, hst0Connect, killstring) 124 | cmd.Stdout = os.Stdout 125 | cmd.Stderr = os.Stderr 126 | err = cmd.Run() 127 | if err != nil { 128 | log.Println("Issue killing Ledger") 129 | log.Println(err) 130 | } 131 | log.Println("> killing auditor") 132 | // auditor 133 | hst1Connect := ae.ac.auditorHostname 134 | if *user != "" { 135 | hst1Connect = *user + "@" + ae.ac.auditorHostname 136 | } 137 | cmd = exec.Command(sshName, hst1Connect, killstring) 138 | cmd.Stdout = os.Stdout 139 | cmd.Stderr = os.Stderr 140 | err = cmd.Run() 141 | if err != nil { 142 | log.Println("Issue killing Auditor") 143 | log.Println(err) 144 | } 145 | for i := 0; i < len(bankHostsFlag); i++ { 146 | hstiConnect := bankHostsFlag[i] 147 | if *user != "" { 148 | hstiConnect = *user + "@" + bankHostsFlag[i] 149 | } 150 | log.Println("> killing bank" + strconv.Itoa(i)) 151 | cmd = exec.Command(sshName, hstiConnect, killstring) 152 | cmd.Stdout = os.Stdout 153 | cmd.Stderr = os.Stderr 154 | err = cmd.Run() 155 | if err != nil { 156 | log.Println("Issue killing Bank " + strconv.Itoa(i)) 157 | log.Println(err) 158 | } 159 | } 160 | 161 | return 162 | } 163 | 164 | func common_args(ae *APLEnvironment) []string { 165 | return []string{ 166 | "-num=" + fmt.Sprintf("%d", len(ae.Banks)), 167 | "-pn=" + fmt.Sprintf("%v", *parallelizeNotify), 168 | "-pv=" + fmt.Sprintf("%v", *parallelizeVerify), 169 | "-rp=" + fmt.Sprintf("%v", *rpOutside), 170 | "-wa=" + fmt.Sprintf("%v", *waitAppend), 171 | "-wn=" + fmt.Sprintf("%v", *waitNotify), 172 | "-et=" + fmt.Sprintf("%v", *emptyTxn), 173 | "-re=" + fmt.Sprintf("%v", *reduce), 174 | debugString, 175 | } 176 | } 177 | 178 | func (ae *APLEnvironment) start_local(ntxn int, testID string, numBanksTransacting int, auditFunction string) { 179 | runLedger := "./apl-ledger" 180 | runBank := "./apl-bank" 181 | runAuditor := "./apl-auditor" 182 | localhost := "localhost" 183 | defaultHost := localhost 184 | for i := 0; i < len(ae.Banks)-1; i++ { 185 | defaultHost = defaultHost + "," + localhost 186 | } 187 | 188 | if *isWindows { 189 | log.Println("> Adjusting for Windows Machine (.exe ftw!)") 190 | runLedger += ".exe" 191 | runBank += ".exe" 192 | runAuditor += ".exe" 193 | } 194 | 195 | largs := append([]string{ 196 | "-bh=" + defaultHost, 197 | }, common_args(ae)...) 198 | 199 | // start ledger 200 | ae.Ledger = exec.Command(runLedger, largs...) 201 | 202 | fmt.Println(ae.Ledger.Args) 203 | ae.Ledger.Stdout = os.Stdout 204 | ae.Ledger.Stderr = os.Stderr 205 | err := ae.Ledger.Start() 206 | check(err, "Problem with ledger") 207 | 208 | aargs := append([]string{ 209 | "-bh=" + defaultHost, 210 | "-testID=" + testID, 211 | "-t=" + auditFunction, 212 | }, common_args(ae)...) 213 | 214 | // start auditor 215 | ae.Auditor = exec.Command(runAuditor, aargs...) 216 | //ae.Auditor.Stdout = os.Stdout 217 | ae.Auditor.Stderr = os.Stderr 218 | ae.AuditorReadPipe, err = ae.Auditor.StdoutPipe() 219 | fmt.Println(ae.Auditor.Args) 220 | scanner := bufio.NewScanner(ae.AuditorReadPipe) 221 | go func(scanner *bufio.Scanner) { 222 | for scanner.Scan() { 223 | txt := scanner.Text() 224 | fmt.Println(txt) 225 | if strings.Contains(txt, "Auditing time") { 226 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 227 | dur, err := time.ParseDuration(tp) 228 | if err != nil { 229 | panic(err) 230 | } 231 | ae.auditing = dur 232 | } 233 | if strings.Contains(txt, "withcache stderr") { 234 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 235 | dur, err := time.ParseDuration(tp) 236 | if err != nil { 237 | panic(err) 238 | } 239 | ae.stderr = dur 240 | } 241 | if strings.Contains(txt, "withcache stddev") { 242 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 243 | dur, err := time.ParseDuration(tp) 244 | if err != nil { 245 | panic(err) 246 | } 247 | ae.stddev = dur 248 | } 249 | if txt == "done" { 250 | ae.auditorStatus <- true 251 | } 252 | } 253 | }(scanner) 254 | 255 | ae.AuditorWritePipe, err = ae.Auditor.StdinPipe() 256 | check(err, "Problem setting up auditor input pipe") 257 | err = ae.Auditor.Start() 258 | check(err, "Problem with auditor") 259 | 260 | // start banks 261 | args := []string{ 262 | runBank, 263 | fmt.Sprintf("-num=%d", len(ae.Banks)), 264 | fmt.Sprintf("-ntxn=%d", ntxn), 265 | "-t=big", 266 | "-bh=" + defaultHost, 267 | fmt.Sprintf("-pn=%v", *parallelizeNotify), 268 | fmt.Sprintf("-pv=%v", *parallelizeVerify), 269 | fmt.Sprintf("-rp=%v", *rpOutside), 270 | fmt.Sprintf("-wa=%v", *waitAppend), 271 | fmt.Sprintf("-wn=%v", *waitNotify), 272 | fmt.Sprintf("-et=%v", *emptyTxn), 273 | fmt.Sprintf("-re=%v", *reduce), 274 | "-testID=" + testID, 275 | debugString} 276 | 277 | bargs := append([]string{ 278 | "-ntxn=" + fmt.Sprintf("%d", ntxn), 279 | "-t=big", 280 | "-bh=" + defaultHost, 281 | "-testID=" + testID, 282 | }, common_args(ae)...) 283 | 284 | for i := 0; i < len(ae.Banks); i++ { 285 | if i >= numBanksTransacting { // we've reached our quota for txing banks 286 | if !(*isWindows) { 287 | ae.Banks[i] = exec.Command("sh", "-c", strings.Join(args, " ")+fmt.Sprintf(" -id=%d", i)+" -noTX=true") 288 | } else { 289 | xargs := append(bargs, []string{fmt.Sprintf("-id=%d", i), "-noTX=true"}...) 290 | ae.Banks[i] = exec.Command( 291 | runBank, 292 | xargs...) 293 | } 294 | } else { 295 | if !(*isWindows) { 296 | ae.Banks[i] = exec.Command("sh", "-c", strings.Join(args, " ")+fmt.Sprintf(" -id=%d", i)) 297 | } else { 298 | xargs := append(bargs, []string{fmt.Sprintf("-id=%d", i)}...) 299 | ae.Banks[i] = exec.Command( 300 | runBank, 301 | xargs...) 302 | } 303 | } 304 | //ae.Banks[i].Stdout = os.Stdout 305 | fmt.Println(ae.Banks[i].Args) 306 | ae.Banks[i].Stderr = os.Stderr 307 | ae.BankReadPipes[i], err = ae.Banks[i].StdoutPipe() 308 | 309 | scanner := bufio.NewScanner(ae.BankReadPipes[i]) 310 | go func(scanner *bufio.Scanner, i int) { 311 | for scanner.Scan() { 312 | txt := scanner.Text() 313 | if !strings.Contains(txt, "wrong number") && !strings.Contains(txt, "method") { 314 | fmt.Println(txt) 315 | } 316 | if txt == "done" { 317 | ae.bankTally <- 1 318 | } 319 | if strings.Contains(txt, "Transactions per second") { 320 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 321 | fmt.Println(tp) 322 | tpn, err := strconv.ParseFloat(tp, 64) 323 | if err != nil { 324 | panic(err) 325 | } 326 | ae.throughput[i] = tpn 327 | } 328 | if strings.Contains(txt, "Latency") { 329 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 330 | dur, err := time.ParseDuration(tp) 331 | if err != nil { 332 | panic(err) 333 | } 334 | fmt.Println(dur) 335 | ae.latency[i] = dur 336 | } 337 | } 338 | }(scanner, i) 339 | 340 | check(err, "failed to set up bank pipe", i) 341 | err = ae.Banks[i].Start() 342 | check(err, "Problem with bank", i) 343 | } 344 | } 345 | 346 | func (ae *APLEnvironment) start_remote(ntxn int, testID string, numBanksTransacting int, auditFunction string) { 347 | runLedger := "/home/" + *user + "/apl-ledger" 348 | runAuditor := "/home/" + *user + "/apl-auditor" 349 | runBank := "/home/" + *user + "/apl-bank" 350 | 351 | // start ledger 352 | hst0Connect := ae.ac.ledgerHostname 353 | if *user != "" { 354 | hst0Connect = *user + "@" + ae.ac.ledgerHostname 355 | } 356 | log.Println("> Starting Ledger!") 357 | ae.Ledger = exec.Command(sshName, hst0Connect, 358 | runLedger, 359 | "-num="+fmt.Sprintf("%d", len(ae.Banks)), 360 | "-bh="+bankHostsFlag.CommaString(), 361 | "-ah="+fmt.Sprintf("%v", ae.ac.auditorHostname), 362 | "-pn="+fmt.Sprintf("%v", *parallelizeNotify), 363 | "-pv="+fmt.Sprintf("%v", *parallelizeVerify), 364 | "-rp="+fmt.Sprintf("%v", *rpOutside), 365 | "-re="+fmt.Sprintf("%v", *reduce), 366 | "-wn="+fmt.Sprintf("%v", *waitNotify), 367 | "-wa="+fmt.Sprintf("%v", *waitAppend), 368 | "-et="+fmt.Sprintf("%v", *emptyTxn), 369 | debugString) 370 | ae.Ledger.Stdout = os.Stdout 371 | ae.Ledger.Stderr = os.Stderr 372 | err := ae.Ledger.Start() 373 | check(err, "Problem with ledger") 374 | fmt.Println(ae.Ledger.Args) 375 | // start auditor 376 | hst1Connect := *auditorHostname 377 | if *user != "" { 378 | hst1Connect = *user + "@" + *auditorHostname 379 | } 380 | log.Println("> Starting Auditor!") 381 | ae.Auditor = exec.Command(sshName, hst1Connect, 382 | runAuditor, 383 | "-num="+fmt.Sprintf("%d", len(ae.Banks)), 384 | "-bh="+bankHostsFlag.CommaString(), 385 | "-testID", testID, 386 | "-pn="+fmt.Sprintf("%v", *parallelizeNotify), 387 | "-pv="+fmt.Sprintf("%v", *parallelizeVerify), 388 | "-rp="+fmt.Sprintf("%v", *rpOutside), 389 | "-re="+fmt.Sprintf("%v", *reduce), 390 | "-wn="+fmt.Sprintf("%v", *waitNotify), 391 | "-wa="+fmt.Sprintf("%v", *waitAppend), 392 | "-et="+fmt.Sprintf("%v", *emptyTxn), 393 | "-t="+auditFunction, 394 | debugString) 395 | //ae.Auditor.Stdout = os.Stdout 396 | ae.Auditor.Stderr = os.Stderr 397 | ae.AuditorReadPipe, err = ae.Auditor.StdoutPipe() 398 | fmt.Println(ae.Auditor.Args) 399 | scanner := bufio.NewScanner(ae.AuditorReadPipe) 400 | go func(scanner *bufio.Scanner) { 401 | for scanner.Scan() { 402 | txt := scanner.Text() 403 | if !strings.Contains(txt, "wrong number") && !strings.Contains(txt, "method") { 404 | fmt.Println(txt) 405 | } 406 | if strings.Contains(txt, "Auditing time") { 407 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 408 | dur, err := time.ParseDuration(tp) 409 | if err != nil { 410 | panic(err) 411 | } 412 | ae.auditing = dur 413 | } 414 | if strings.Contains(txt, "stderr") { 415 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 416 | dur, err := time.ParseDuration(tp) 417 | if err != nil { 418 | panic(err) 419 | } 420 | ae.stderr = dur 421 | } 422 | if strings.Contains(txt, "stddev") { 423 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 424 | dur, err := time.ParseDuration(tp) 425 | if err != nil { 426 | panic(err) 427 | } 428 | ae.stddev = dur 429 | } 430 | 431 | if txt == "done" { 432 | ae.auditorStatus <- true 433 | } 434 | } 435 | }(scanner) 436 | 437 | ae.AuditorWritePipe, err = ae.Auditor.StdinPipe() 438 | check(err, "Problem setting up auditor input pipe") 439 | err = ae.Auditor.Start() 440 | check(err, "Problem with auditor") 441 | 442 | // start banks 443 | args := []string{runBank, 444 | fmt.Sprintf("-num=%d", len(ae.Banks)), 445 | fmt.Sprintf("-ntxn=%d", ntxn), 446 | "-t=big", 447 | "-lh=" + *ledgerHostname, 448 | "-bh=" + bankHostsFlag.CommaString(), 449 | fmt.Sprintf("-pn=%v", *parallelizeNotify), 450 | fmt.Sprintf("-pv=%v", *parallelizeVerify), 451 | fmt.Sprintf("-rp=%v", *rpOutside), 452 | fmt.Sprintf("-re=%v", *reduce), 453 | fmt.Sprintf("-wn=%v", *waitNotify), 454 | fmt.Sprintf("-et=%v", *emptyTxn), 455 | fmt.Sprintf("-wa=%v", *waitAppend), 456 | "-testID=" + testID, 457 | debugString} 458 | 459 | for i := 0; i < len(ae.Banks); i++ { 460 | hstiConnect := bankHostsFlag[i] 461 | if *user != "" { 462 | hstiConnect = *user + "@" + bankHostsFlag[i] 463 | } 464 | 465 | if i >= numBanksTransacting { // we've reached our quota for txing banks 466 | log.Println("> Starting bank " + strconv.Itoa(i) + " but not transacting") 467 | ae.Banks[i] = exec.Command("sh", "-c", sshName+" "+hstiConnect+" "+strings.Join(args, " ")+fmt.Sprintf(" -id=%d", i)+" -noTX=true") 468 | } else { 469 | log.Println("> Starting bank " + strconv.Itoa(i)) 470 | ae.Banks[i] = exec.Command("sh", "-c", sshName+" "+hstiConnect+" "+strings.Join(args, " ")+fmt.Sprintf(" -id=%d", i)) 471 | } 472 | //ae.Banks[i].Stdout = os.Stdout 473 | ae.Banks[i].Stderr = os.Stderr 474 | ae.BankReadPipes[i], err = ae.Banks[i].StdoutPipe() 475 | //fmt.Println(ae.Banks[i].Args) 476 | scanner := bufio.NewScanner(ae.BankReadPipes[i]) 477 | go func(scanner *bufio.Scanner, i int) { 478 | for scanner.Scan() { 479 | txt := scanner.Text() 480 | 481 | if !strings.Contains(txt, "wrong number") && !strings.Contains(txt, "method") { 482 | fmt.Println(txt) 483 | } 484 | if txt == "done" { 485 | ae.bankTally <- 1 486 | } 487 | if strings.Contains(txt, "Transactions per second") { 488 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 489 | tpn, err := strconv.ParseFloat(tp, 64) 490 | if err != nil { 491 | panic(err) 492 | } 493 | ae.throughput[i] = tpn 494 | } 495 | if strings.Contains(txt, "Latency") { 496 | tp := strings.Trim(strings.Split(txt, ":")[1], " ") 497 | dur, err := time.ParseDuration(tp) 498 | if err != nil { 499 | panic(err) 500 | } 501 | ae.latency[i] = dur 502 | } 503 | 504 | } 505 | }(scanner, i) 506 | 507 | check(err, "failed to set up bank pipe", i) 508 | err = ae.Banks[i].Start() 509 | check(err, "Problem with bank", i) 510 | } 511 | } 512 | 513 | ///////// LOCAL FUNCTIONS 514 | 515 | func build_local() { 516 | for b := range binaries { 517 | cmd := exec.Command("go", "build", fmt.Sprintf("github.com/mit-dci/zkledger/cmd/%s", binaries[b])) 518 | cmd.Stdout = os.Stdout 519 | cmd.Stderr = os.Stderr 520 | err := cmd.Run() 521 | if err != nil { 522 | log.Fatal(err) 523 | } 524 | } 525 | } 526 | 527 | ///////// REMOTE FUNCTIONS 528 | 529 | func build_remote() { 530 | for b := range binaries { 531 | cmd := exec.Command("env", "GOOS=linux", "GOARCH=amd64", "go", "build", fmt.Sprintf("github.com/mit-dci/zkledger/cmd/%s", binaries[b])) 532 | cmd.Stdout = os.Stdout 533 | cmd.Stderr = os.Stderr 534 | err := cmd.Run() 535 | if err != nil { 536 | log.Fatal(err) 537 | } 538 | log.Println("Compiled:", binaries[b]) 539 | } 540 | } 541 | 542 | func scp() { 543 | log.Println("> Sending files to remote servers") 544 | 545 | runLedger := "/home/" + *user + "/apl-ledger" 546 | runBank := "/home/" + *user + "/apl-bank" 547 | runAuditor := "/home/" + *user + "/apl-auditor" 548 | 549 | // ledger 550 | hst0Connect := *ledgerHostname 551 | if *user != "" { 552 | hst0Connect = *user + "@" + *ledgerHostname + ":" + runLedger 553 | } 554 | 555 | // copy it over 556 | log.Println("> Sending Ledger to", *ledgerHostname) 557 | cmd := exec.Command(scpName, "apl-ledger", hst0Connect) 558 | cmd.Stdout = os.Stdout 559 | cmd.Stderr = os.Stderr 560 | err := cmd.Run() 561 | if err != nil { 562 | log.Fatal(err) 563 | } 564 | 565 | // chmod it to be executable 566 | cmd2 := exec.Command(sshName, hst0Connect[:len(hst0Connect)-len(runLedger)-1], "chmod 770 "+runLedger) // [:-2] removes the :~ 567 | cmd2.Stdout = os.Stdout 568 | cmd2.Stderr = os.Stderr 569 | err2 := cmd2.Run() 570 | if err2 != nil { 571 | log.Fatal(err2) 572 | } 573 | 574 | // auditor 575 | hst1Connect := *auditorHostname 576 | if *user != "" { 577 | hst1Connect = *user + "@" + *auditorHostname + ":" + runAuditor 578 | } 579 | 580 | // copy it over 581 | log.Println("> Sending Auditor to ", *auditorHostname) 582 | cmd = exec.Command(scpName, "apl-auditor", hst1Connect) 583 | cmd.Stdout = os.Stdout 584 | cmd.Stderr = os.Stderr 585 | err = cmd.Run() 586 | if err != nil { 587 | log.Fatal(err) 588 | } 589 | 590 | // chmod it to be executable 591 | cmd2 = exec.Command(sshName, hst1Connect[:len(hst1Connect)-len(runAuditor)-1], "chmod 770 "+runAuditor) // [:-2] removes the :~ 592 | cmd2.Stdout = os.Stdout 593 | cmd2.Stderr = os.Stderr 594 | err2 = cmd2.Run() 595 | if err2 != nil { 596 | log.Fatal(err2) 597 | } 598 | 599 | log.Println("> Sending banks to", bankHostsFlag) 600 | var wg sync.WaitGroup 601 | for i := 0; i < len(bankHostsFlag); i++ { 602 | wg.Add(1) 603 | go func(i int) { 604 | defer wg.Done() 605 | hstiConnect := bankHostsFlag[i] 606 | if *user != "" { 607 | hstiConnect = *user + "@" + bankHostsFlag[i] + ":" + runBank 608 | } 609 | 610 | log.Println("> Sending bank " + strconv.Itoa(i) + " to " + bankHostsFlag[i]) 611 | cmd = exec.Command(scpName, "apl-bank", hstiConnect) 612 | cmd.Stdout = os.Stdout 613 | cmd.Stderr = os.Stderr 614 | err = cmd.Run() 615 | if err != nil { 616 | log.Fatal(err) 617 | } 618 | 619 | // chmod it to be executable 620 | cmd2 = exec.Command(sshName, hstiConnect[:len(hstiConnect)-len(runBank)-1], "chmod 770 "+runBank) // [:-2] removes the :~ 621 | cmd2.Stdout = os.Stdout 622 | cmd2.Stderr = os.Stderr 623 | err2 = cmd2.Run() 624 | if err2 != nil { 625 | log.Fatal(err2) 626 | } 627 | }(i) 628 | } 629 | wg.Wait() 630 | } 631 | 632 | // TBD 633 | 634 | type TestCase struct { 635 | Name string 636 | NumTXN int 637 | Local bool 638 | MinBankCount int 639 | MaxBankCount int 640 | BankStep int 641 | MinNumTX int 642 | MaxNumTX int 643 | TXStep int 644 | AuditFunction string 645 | } 646 | 647 | type APLConfig struct { 648 | numBanks int 649 | remote bool 650 | debug bool 651 | user string 652 | auditorHostname string 653 | ledgerHostname string 654 | bankHostnames []string 655 | testName string 656 | } 657 | 658 | /// 659 | -------------------------------------------------------------------------------- /cmd/setup/keys/b0_pk: -------------------------------------------------------------------------------- 1 | 31162737974914322510223911493259949908325790533701417645370598536038546760813,3243957534678192772627433866145815496382252068439063004526717165758982279478 -------------------------------------------------------------------------------- /cmd/setup/keys/b0_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b0_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b10_pk: -------------------------------------------------------------------------------- 1 | 91269697117267099984459566631239464356271531293440219263306852460275344056821,57856811126255535609588975045621607920040922473844581769794380055346268746034 -------------------------------------------------------------------------------- /cmd/setup/keys/b10_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b10_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b11_pk: -------------------------------------------------------------------------------- 1 | 24745757527564333614534015603049569664821034165072087950328196878615037651867,26025914461571091845102890894750226915851513118786051203023213954276961000137 -------------------------------------------------------------------------------- /cmd/setup/keys/b11_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b11_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b12_pk: -------------------------------------------------------------------------------- 1 | 10071938457509765208176437393689720359918900970524139788421997397326362437275,89512342004854486862664082868193474448959271973553166185925458227194385562509 -------------------------------------------------------------------------------- /cmd/setup/keys/b12_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b12_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b13_pk: -------------------------------------------------------------------------------- 1 | 26980766966861505409440601215803391792261033476846074617983722628702541682457,58968377318155166815087504926397855576753884334829261927558848609333058777289 -------------------------------------------------------------------------------- /cmd/setup/keys/b13_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b13_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b14_pk: -------------------------------------------------------------------------------- 1 | 62560634861317304871399013014047908256686239809205654643915795461196148257599,105317050855373995952640958084853995788100860369709149419072537753645618230309 -------------------------------------------------------------------------------- /cmd/setup/keys/b14_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b14_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b15_pk: -------------------------------------------------------------------------------- 1 | 53688220566939948169874335910299995133189542876347696925303843633591049867550,70671468457628673211764239503167895990795677560126594872276487889926197391572 -------------------------------------------------------------------------------- /cmd/setup/keys/b15_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b15_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b16_pk: -------------------------------------------------------------------------------- 1 | 50025540027085003249672781131877540210147131176371076085370159556389948637124,21145760914016392368365205018219200494394006315436514769098073253034626573490 -------------------------------------------------------------------------------- /cmd/setup/keys/b16_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b16_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b17_pk: -------------------------------------------------------------------------------- 1 | 106189345473902606956841418909701336849473200372566539199342324613251057898145,44079131914766130129092439835579729791924860747385761689450003715614439602107 -------------------------------------------------------------------------------- /cmd/setup/keys/b17_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b17_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b18_pk: -------------------------------------------------------------------------------- 1 | 102311915433490777514730392553900610486478213395503141280788539583037150958132,69285382640746956956176954823396909790354638678345995017404609959892492039951 -------------------------------------------------------------------------------- /cmd/setup/keys/b18_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b18_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b19_pk: -------------------------------------------------------------------------------- 1 | 57543451355327428953916308065257280227300897804181157084995820994405699801626,58232610359199388876514603344672453333824781230141273943382037163757462145493 -------------------------------------------------------------------------------- /cmd/setup/keys/b19_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b19_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b1_pk: -------------------------------------------------------------------------------- 1 | 104306669726597258552457800704291913924157442819741684968539853652305339195302,59723646933547178320805231501800256566404530244961528445232623018526217031402 -------------------------------------------------------------------------------- /cmd/setup/keys/b1_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b1_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b20_pk: -------------------------------------------------------------------------------- 1 | 113778025033448982771544647946694239351407143691652020046920596654162516070549,32207591680888773624365737424058029357055963915654868706244884217912728966182 -------------------------------------------------------------------------------- /cmd/setup/keys/b20_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b20_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b21_pk: -------------------------------------------------------------------------------- 1 | 100873365389412912631763901805526167918799624961913945216517981211774701757144,66871869249676448889861731681188767868106397806953798776739307786371745382140 -------------------------------------------------------------------------------- /cmd/setup/keys/b21_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b21_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b22_pk: -------------------------------------------------------------------------------- 1 | 1102921337555653421077397929405006589952872915396591081058988145601163632175,4090538437426938469808868599750084382373769196383154861011173142727622044627 -------------------------------------------------------------------------------- /cmd/setup/keys/b22_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b22_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b23_pk: -------------------------------------------------------------------------------- 1 | 39056722633979252441720926777597397996016252060644672498501149275038519428230,74192108202435946828591762269022697391495021291718668189167239278963122753243 -------------------------------------------------------------------------------- /cmd/setup/keys/b23_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b23_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b24_pk: -------------------------------------------------------------------------------- 1 | 24403111807717568058221855698063746612665094692634445427619667212493799778633,80527966358129820485781251514831034677699736121397894113561448174822449802375 -------------------------------------------------------------------------------- /cmd/setup/keys/b24_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b24_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b25_pk: -------------------------------------------------------------------------------- 1 | 34821777066933822464110938381265238664343607599047391392713272828112391733001,84741163048213261163527843739821002506018212399983355777157892719061280241927 -------------------------------------------------------------------------------- /cmd/setup/keys/b25_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b25_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b26_pk: -------------------------------------------------------------------------------- 1 | 96700380331329439939398844542755370233019876036379592855356095952592499518176,84439704733468813568382390933356727888813142279510042812805882541658326910516 -------------------------------------------------------------------------------- /cmd/setup/keys/b26_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b26_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b27_pk: -------------------------------------------------------------------------------- 1 | 32675049822103138922525524399878776664102990609460949389338963624106077948839,93865904359450278874391958576787136593158123032336354710991383925717201803315 -------------------------------------------------------------------------------- /cmd/setup/keys/b27_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b27_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b28_pk: -------------------------------------------------------------------------------- 1 | 65818118478138166006473647340662112371006570411050648880746253831648429451100,25375200939571587740208034619706326170538777287873934967943118717683047388385 -------------------------------------------------------------------------------- /cmd/setup/keys/b28_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b28_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b29_pk: -------------------------------------------------------------------------------- 1 | 52519690080601085903119330652473100169651685452874284256713985786292094260870,102543634216275997877407899393039530603866312212219981742091767367591365913812 -------------------------------------------------------------------------------- /cmd/setup/keys/b29_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b29_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b2_pk: -------------------------------------------------------------------------------- 1 | 78990978055875482213519426577566655084235914353126259846189426580585978191425,14838356030615363985994465553279457831477711117352611982834955835709977276603 -------------------------------------------------------------------------------- /cmd/setup/keys/b2_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b2_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b30_pk: -------------------------------------------------------------------------------- 1 | 26990125332655643925875891845656739261757405989689919197601152687094561065983,30364307786412750299437718183392500083074517273835492051138769564305516631509 -------------------------------------------------------------------------------- /cmd/setup/keys/b30_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b30_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b31_pk: -------------------------------------------------------------------------------- 1 | 108587203289406122412384042087367496101080028162091442980068960531576749312966,27145303334704875539936140570653352345579910989230619108180859599106478912390 -------------------------------------------------------------------------------- /cmd/setup/keys/b31_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b31_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b32_pk: -------------------------------------------------------------------------------- 1 | 108294835240900888658031394182005463981558674072519575194775301441541740350828,12950264665686039612063676117433033342065654204836750207502321918822588019231 -------------------------------------------------------------------------------- /cmd/setup/keys/b32_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b32_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b33_pk: -------------------------------------------------------------------------------- 1 | 108918221651556307871461672224670392518005093801540593719365869060574329911342,33621276389234949187999050068937763586516031937762808422288498821432500919812 -------------------------------------------------------------------------------- /cmd/setup/keys/b33_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b33_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b34_pk: -------------------------------------------------------------------------------- 1 | 24321428707270041530717851679428161735166430735524266543820298332671186848361,83653356914635158737412663151903934262763428966039733219568924879374965593097 -------------------------------------------------------------------------------- /cmd/setup/keys/b34_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b34_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b35_pk: -------------------------------------------------------------------------------- 1 | 77052046575351160936272800336599624430374033061655907446213548241394596564670,31822820674398669395088104792011477814853148717621056642568680803049836673354 -------------------------------------------------------------------------------- /cmd/setup/keys/b35_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b35_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b36_pk: -------------------------------------------------------------------------------- 1 | 15039158541847590258238540310188577119348222162991134794762840421343517037757,18643706338969097192015976715624274378805158262324779690247688852363713284054 -------------------------------------------------------------------------------- /cmd/setup/keys/b36_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b36_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b37_pk: -------------------------------------------------------------------------------- 1 | 79136878878948981282649623250469585646793144428761780554771726019382542735188,19928301509350531246646499501879210050732898549458116123466152855365767780158 -------------------------------------------------------------------------------- /cmd/setup/keys/b37_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b37_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b38_pk: -------------------------------------------------------------------------------- 1 | 52441113396081021650482005137655641484630040541538016279497923603006283217230,7416400287171668777439577698805189289025597898357436236263702873185430826688 -------------------------------------------------------------------------------- /cmd/setup/keys/b38_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b38_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b39_pk: -------------------------------------------------------------------------------- 1 | 81762751713487313226748208247010397897537498205329445157035117124438952311095,67642562216083690438456327428472859373463846305140545061044511791012256706838 -------------------------------------------------------------------------------- /cmd/setup/keys/b39_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b39_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b3_pk: -------------------------------------------------------------------------------- 1 | 60284213037711622963860348272688379503451660376614053888286834031195565953917,31555205998050805369326328704358754043154607628971344387956391519812942635882 -------------------------------------------------------------------------------- /cmd/setup/keys/b3_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b3_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b40_pk: -------------------------------------------------------------------------------- 1 | 107936024455510438923603583153389020456546692396448277663993055785090482610640,20785057244130979274388460804444290403714606791587053029240896491394986242273 -------------------------------------------------------------------------------- /cmd/setup/keys/b40_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b40_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b41_pk: -------------------------------------------------------------------------------- 1 | 42926137396100114788309340052914610022593217968475509671967116612327944089268,13093592151280116236715471141119199383421499594947507078043994282642641559364 -------------------------------------------------------------------------------- /cmd/setup/keys/b41_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b41_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b42_pk: -------------------------------------------------------------------------------- 1 | 111910862962211416659225483112952554209815182450226407835876357553506161744115,2686937856826672843336506971498398553858465478751656838724074953268587128919 -------------------------------------------------------------------------------- /cmd/setup/keys/b42_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b42_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b43_pk: -------------------------------------------------------------------------------- 1 | 64267799526278199329351913129406045085817835490946044357449726479184689677145,10325296962927244285887728369291668918373438076998962404998344386923516947837 -------------------------------------------------------------------------------- /cmd/setup/keys/b43_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b43_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b44_pk: -------------------------------------------------------------------------------- 1 | 22755632305058035761114085036759351818709990980681339468094790129219582959004,45236921238145818299534912081622243556164778730722495686821616680319923468046 -------------------------------------------------------------------------------- /cmd/setup/keys/b44_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b44_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b45_pk: -------------------------------------------------------------------------------- 1 | 36791597396193231394590603299134696466083220105116937578631199128319514201703,70225021013540670301622640519932709489344378472693773952705399305579657092709 -------------------------------------------------------------------------------- /cmd/setup/keys/b45_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b45_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b46_pk: -------------------------------------------------------------------------------- 1 | 62654935750030070953497480223065443367420343254900136950305762548661546612168,96408500379500925967343380028848599883006982874665363532697852024840037351958 -------------------------------------------------------------------------------- /cmd/setup/keys/b46_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b46_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b47_pk: -------------------------------------------------------------------------------- 1 | 110458616433670994111927209365389899844321187357949257568353068529696321162747,19754835716571914065580968281642407277368146523773262366702888193873305461769 -------------------------------------------------------------------------------- /cmd/setup/keys/b47_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b47_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b48_pk: -------------------------------------------------------------------------------- 1 | 102128880905922693964888226226562676261159689157846651794330487234825031672240,39273668274360575141031863631444946141386067257250848952279714750113217342353 -------------------------------------------------------------------------------- /cmd/setup/keys/b48_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b48_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b49_pk: -------------------------------------------------------------------------------- 1 | 107242643127855380000212802243952928829837465785225904351142633871241861572264,75347310659472134391368830409843925782582302013812742296289597662676838832381 -------------------------------------------------------------------------------- /cmd/setup/keys/b49_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b49_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b4_pk: -------------------------------------------------------------------------------- 1 | 102605005503657048844899976679285238335894665717930883745202199910301605030990,57237214829685297877134593087726165698310260018308888716770281719807528966376 -------------------------------------------------------------------------------- /cmd/setup/keys/b4_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b4_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b5_pk: -------------------------------------------------------------------------------- 1 | 33247156330843618756421782516731649971096154775224981513761063902036121708710,62697109650328677574764089096486492880742598546600740016142599731929929320684 -------------------------------------------------------------------------------- /cmd/setup/keys/b5_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b5_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b6_pk: -------------------------------------------------------------------------------- 1 | 78139031806931218732867663180376235850476762053706878762506323328554265333905,70482470438499769409322699720228167617713403980092729171875163412517859831494 -------------------------------------------------------------------------------- /cmd/setup/keys/b6_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b6_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b7_pk: -------------------------------------------------------------------------------- 1 | 108638573037853427255352697926623303133903382732234746658067395983740352756287,90016415137411616367719751042315126577333572116330869435070961251259265917123 -------------------------------------------------------------------------------- /cmd/setup/keys/b7_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b7_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b8_pk: -------------------------------------------------------------------------------- 1 | 78172615808468648990540026737596978538135068541916351651888178154895948212144,44896383148238339144906723222240296501477242214165057954975607767209655113937 -------------------------------------------------------------------------------- /cmd/setup/keys/b8_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b8_sk -------------------------------------------------------------------------------- /cmd/setup/keys/b9_pk: -------------------------------------------------------------------------------- 1 | 20514500956742880545815277686171115413229885756299507177775555291816935882309,77509090075823905644294696043077171748437874345099923792592302012861367177681 -------------------------------------------------------------------------------- /cmd/setup/keys/b9_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/b9_sk -------------------------------------------------------------------------------- /cmd/setup/keys/is_pk: -------------------------------------------------------------------------------- 1 | 104597657332180700732862897786513766669655094268388302589461598923822453112374,51659256023242095536989650590244254087257334458253939072448084726506084032326 -------------------------------------------------------------------------------- /cmd/setup/keys/is_sk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/cmd/setup/keys/is_sk -------------------------------------------------------------------------------- /cmd/setup/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "fmt" 7 | "io" 8 | "log" 9 | "strconv" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | var remote = flag.Bool("remote", false, "Run remotely (not localhost)") 15 | var numBanks = flag.Int("numbanks", 2, "Number of banks") 16 | var debug = flag.Bool("debug", false, "Run debug") 17 | var isWindows = flag.Bool("windows", false, "Used to append '.exe' when executing files") 18 | var user = flag.String("user", "", "Username for logging in remotely") 19 | var auditorHostname = flag.String("ah", "localhost", "Hostname for the auditor") 20 | var ledgerHostname = flag.String("lh", "localhost", "Hostname for the ledger") 21 | var testName = flag.String("t", "basic", "Test to run: simple,alternateBanks10") 22 | var skipBuilding = flag.Bool("skipBuild", false, "Skip building the files") 23 | var skipCopying = flag.Bool("skipCopy", false, "Skip copying files to remote servers") 24 | var parallelizeNotify = flag.Bool("pn", true, "Send notifications in parallel") 25 | var parallelizeVerify = flag.Bool("pv", true, "Parallelize verification") 26 | var rpOutside = flag.Bool("rp", true, "Generate 0 Range Proofs outside of lock") 27 | var ntxn = flag.Int("ntxn", 100, "Number of transactions in simple experiment") 28 | var reduce = flag.Bool("re", false, "Reduce size of txns") 29 | var waitAppend = flag.Bool("wa", true, "Wait for AppendTxn to return before returning from CreateEncryptedTransaction") 30 | var waitNotify = flag.Bool("wn", true, "Wait for ledger to notify everyone before releasing lock") 31 | var emptyTxn = flag.Bool("et", false, "Send around empty txns and no verifying") 32 | 33 | type hostnames []string 34 | 35 | var bankHostsFlag hostnames 36 | var debugString string 37 | var sshName string 38 | var scpName string 39 | var binaries []string = []string{"apl-bank", "apl-ledger", "apl-auditor"} 40 | 41 | func (h *hostnames) String() string { 42 | return fmt.Sprint(*h) 43 | } 44 | 45 | func (h *hostnames) CommaString() string { 46 | result := "" 47 | for _, host := range *h { 48 | result += host + "," 49 | } 50 | return result[:len(result)-1] 51 | } 52 | 53 | func (h *hostnames) Set(value string) error { 54 | if len(*h) > 0 { 55 | return errors.New("hostnames flag already set") 56 | } 57 | for _, host := range strings.Split(value, ",") { 58 | *h = append(*h, host) 59 | } 60 | return nil 61 | } 62 | 63 | func init() { 64 | flag.Var(&bankHostsFlag, "bh", "comma separated list of hostnames of the banks in order of IDs. Only used if remote==true") 65 | if *isWindows { 66 | sshName = "plink" 67 | scpName = "pscp" 68 | } else { 69 | sshName = "ssh" 70 | scpName = "scp" 71 | } 72 | } 73 | 74 | func check(err error, msg ...interface{}) { 75 | if err != nil { 76 | fmt.Println(msg...) 77 | log.Fatal(err) 78 | } 79 | } 80 | 81 | ///////// TESTS 82 | 83 | // num_txn = txns per creating bank 84 | // nb = num banks 85 | // nc = number of banks creating transactions 86 | func test_simple(testName string, num_txn int, nb int, nc int, remote bool, ac *APLConfig) { 87 | log.Printf("> Starting %s: [%v banks, %v txns, %v creating]\n", testName, nb, num_txn, nc) 88 | log.Printf(":::::::::::::::::: Starting binaries with %d banks!\n", nb) 89 | log.Printf(":::::::::::::::::: With %d of them transacting!\n", nc) 90 | tn := testName + fmt.Sprintf("_%d_%d_%d_%d", num_txn, nb, nc, time.Now().Unix()) 91 | ae := &APLEnvironment{} 92 | ae.init(nb, remote, ac) 93 | ae.start(num_txn, tn, nc, "h") 94 | 95 | tally := 0 96 | for { 97 | d := <-ae.bankTally 98 | tally += d 99 | if tally == nc { 100 | break 101 | } 102 | } 103 | log.Println(":::::::::::::::::: Auditing all banks!") 104 | go func() { 105 | defer ae.AuditorWritePipe.Close() 106 | io.WriteString(ae.AuditorWritePipe, "\n") 107 | }() 108 | // once we get the tally, begin auditing 109 | <-ae.auditorStatus 110 | 111 | log.Println("> Killing programs") 112 | ae.shutdown() 113 | var total_th float64 114 | for i := 0; i < len(ae.throughput); i++ { 115 | total_th += ae.throughput[i] 116 | } 117 | fmt.Printf(">>> %v/%v transacting %v ntxn per bank. Total throughput: %v, Avg latency: %v, Auditing time: %v, stddev: %v, stderr: %v\n", nc, nb, num_txn, total_th, ae.latency[0], ae.auditing, ae.stddev, ae.stderr) 118 | } 119 | 120 | // runs test_simple many times 121 | func test_step(testName string, 122 | minBankCount int, maxBankCount int, bankStep int, 123 | minNumTX int, maxNumTX int, txStep int, 124 | minTXing int, maxTXing int, txingStep int, 125 | remote bool, 126 | ac *APLConfig) { 127 | log.Println("> Starting " + testName + 128 | ": \n\tBank Range [" + strconv.Itoa(minBankCount) + "," + strconv.Itoa(maxBankCount) + "]\n\t" + 129 | "TX Range [" + strconv.Itoa(minNumTX) + "," + strconv.Itoa(maxNumTX) + "]") 130 | 131 | for curBankCount := minBankCount; curBankCount <= maxBankCount; curBankCount += bankStep { 132 | for curTXCount := minNumTX; curTXCount <= maxNumTX; curTXCount += txStep { 133 | maxTransacting := maxTXing 134 | if maxTransacting > curBankCount { 135 | maxTransacting = curBankCount 136 | } 137 | for curTXingCount := minTXing; curTXingCount <= maxTransacting; curTXingCount += txingStep { 138 | test_simple(testName, curTXCount, curBankCount, curTXingCount, remote, ac) 139 | } 140 | } 141 | } 142 | } 143 | 144 | //////////////////////// 145 | 146 | func main() { 147 | flag.Parse() 148 | ac := &APLConfig{ 149 | numBanks: *numBanks, 150 | remote: *remote, 151 | debug: *debug, 152 | user: *user, 153 | auditorHostname: *auditorHostname, 154 | ledgerHostname: *ledgerHostname, 155 | bankHostnames: bankHostsFlag, 156 | testName: *testName, 157 | } 158 | if ac.debug { 159 | debugString = "-debug=true" 160 | } else { 161 | debugString = "" 162 | } 163 | 164 | if ac.remote { 165 | log.Println("Beginning remote experiment with test:", ac.testName) 166 | 167 | if len(ac.bankHostnames) < 2 { 168 | log.Fatal("Need at least 2 bank hosts to run remote experiment") 169 | } 170 | 171 | if !*skipBuilding { 172 | log.Println("> Compiling code for remote servers") 173 | build_remote() 174 | } 175 | if !*skipCopying { 176 | log.Println("> Binaries built! Transfering them over to servers") 177 | scp() 178 | } 179 | } else { 180 | log.Println("Beginning local experiment with test:", ac.testName) 181 | 182 | log.Println("> Building binaries locally") 183 | if !*skipBuilding { 184 | build_local() 185 | } 186 | } 187 | switch ac.testName { 188 | case "simple1": 189 | test_simple(ac.testName, *ntxn, ac.numBanks, 1, ac.remote, ac) 190 | break 191 | case "simpleall": 192 | test_simple(ac.testName, *ntxn, ac.numBanks, ac.numBanks, ac.remote, ac) 193 | break 194 | case "alternateBanks10": 195 | test_step(ac.testName, 196 | 2, 10, 1, 197 | 5, 5, 1, 198 | 10, 10, 1, ac.remote, ac) 199 | break 200 | case "r50TX_herf": 201 | test_step(ac.testName, 202 | ac.numBanks, ac.numBanks, 1, 203 | 50, 50, 50, 204 | ac.numBanks, ac.numBanks, 1, ac.remote, ac) 205 | break 206 | case "r1kTX_herf": 207 | test_step(ac.testName, 208 | ac.numBanks, ac.numBanks, 1, 209 | 1000, 1000, 1, 210 | ac.numBanks, ac.numBanks, 1, ac.remote, ac) 211 | break 212 | default: 213 | log.Println("** NOT A VALID TESTNAME ** Use: simple1 OR simpleall OR alternateBanks10 OR r50TX_herf OR r1kTX_herf") 214 | break 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /debug.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | ) 7 | 8 | var DEBUG = flag.Bool("debug", false, "Debug output") 9 | 10 | func Dprintf(format string, args ...interface{}) { 11 | if *DEBUG { 12 | fmt.Printf(format, args...) 13 | } 14 | } 15 | 16 | func check(e error) { 17 | if e != nil { 18 | panic(e) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /ledger.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "bytes" 5 | "encoding/gob" 6 | "encoding/json" 7 | "flag" 8 | "fmt" 9 | "io/ioutil" 10 | "log" 11 | "net" 12 | "net/rpc" 13 | "sync" 14 | "time" 15 | ) 16 | 17 | var parallelizeNotify = flag.Bool("pn", false, "Send notifications in parallel") 18 | var waitNotify = flag.Bool("wn", true, "Hold lock on ledger until done notifying") 19 | 20 | type LocalLedger struct { 21 | mu *sync.Mutex 22 | Transactions []EncryptedTransaction 23 | } 24 | 25 | // Everyone has one of these. Used to mirror global ledger. 26 | func MakeLocalLedger() *LocalLedger { 27 | l := &LocalLedger{ 28 | mu: new(sync.Mutex), 29 | Transactions: make([]EncryptedTransaction, 0), 30 | } 31 | return l 32 | } 33 | 34 | func (l *LocalLedger) add(etx *EncryptedTransaction) int { 35 | etx.Index = len(l.Transactions) 36 | l.Transactions = append(l.Transactions, *etx) 37 | return etx.Index 38 | } 39 | 40 | func (l *LocalLedger) DumpLedger(_ *struct{}, _ *struct{}) error { 41 | var buf bytes.Buffer 42 | 43 | fmt.Println("> Dumping binary copy of ledger") 44 | enc := gob.NewEncoder(&buf) 45 | enc.Encode(l.Transactions) 46 | 47 | filename := "ledger_binary_" + fmt.Sprintf("%d", time.Now().UnixNano()) + ".byte" 48 | 49 | err := ioutil.WriteFile(filename, buf.Bytes(), 0666) 50 | check(err) 51 | return err 52 | } 53 | 54 | func (l *LocalLedger) LoadLedger(fn string, _ *struct{}) error { 55 | return nil 56 | } 57 | 58 | func (l *LocalLedger) DumpReadableLedger(_ *struct{}, _ *struct{}) error { 59 | var buf bytes.Buffer 60 | 61 | Dprintf("> Dumping readable copy of ledger\n") 62 | 63 | enc := json.NewEncoder(&buf) 64 | enc.Encode(l.Transactions) 65 | filename := "ledger_readable_" + fmt.Sprintf("%d", time.Now().UnixNano()) + ".log" 66 | err := ioutil.WriteFile(filename, buf.Bytes(), 0666) 67 | check(err) 68 | return err 69 | } 70 | 71 | // Global, single server ledger 72 | type Ledger struct { 73 | LocalLedger 74 | 75 | num int 76 | Banks []BankClient 77 | Auditor AuditorClient 78 | Setup chan struct{} 79 | start time.Time 80 | } 81 | 82 | func (l *Ledger) print_transactions() { 83 | Dprintf("L\t{") 84 | for i := 0; i < len(l.Transactions); i++ { 85 | tx := &l.Transactions[i] 86 | Dprintf("%v/%v:[%v] \n", i, tx.Index, tx.Entries) 87 | } 88 | Dprintf("}\n") 89 | } 90 | 91 | // Main ledger process 92 | func MakeLedger(num int) *Ledger { 93 | l := &Ledger{ 94 | LocalLedger: LocalLedger{ 95 | mu: new(sync.Mutex), 96 | Transactions: make([]EncryptedTransaction, 0), 97 | }, 98 | num: num, 99 | Setup: make(chan struct{}), 100 | } 101 | return l 102 | } 103 | 104 | func (l *Ledger) Go(c APLClientConfig, _ *struct{}) error { 105 | go l.register(c.Hostname, c.BasePort, c.BankHostnames, c.AuditorHostname) 106 | l.listen(c.Hostname, c.BasePort) 107 | return nil 108 | } 109 | 110 | func (l *Ledger) listen(hostname string, basePort int) { 111 | listener, err := net.Listen("tcp", fmt.Sprintf(":%d", basePort)) 112 | if err != nil { 113 | log.Fatalf("[L] Could not listen\n") 114 | } 115 | err = rpc.Register(l) 116 | if err != nil { 117 | panic(err) 118 | } 119 | 120 | for { 121 | conn, err := listener.Accept() 122 | if err != nil { 123 | fmt.Println("[L] ERR accepting:", err) 124 | continue 125 | } 126 | Dprintf("[L] serving connection...\n") 127 | go rpc.ServeConn(conn) 128 | } 129 | } 130 | 131 | func (l *Ledger) register(hostname string, basePort int, bankHostname []string, auditorHostname string) { 132 | var wg sync.WaitGroup 133 | l.Banks = make([]BankClient, l.num) 134 | for i := 0; i < l.num; i++ { 135 | wg.Add(1) 136 | go func(i int) { 137 | x := MakeRemoteBankClient() 138 | x.connect(bankHostname[i], basePort+i+1) 139 | l.Banks[i] = x 140 | Dprintf("[L] Connected to bank %v\n", i) 141 | wg.Done() 142 | }(i) 143 | } 144 | wg.Add(1) 145 | go func() { // TODO: Change this in order to support delayed auditor start or multiple auditors 146 | x := MakeRemoteAuditorClient() 147 | x.connect(auditorHostname, basePort+l.num+2) 148 | l.Auditor = x 149 | Dprintf("[L] Connected to auditor\n") 150 | wg.Done() 151 | }() 152 | wg.Wait() 153 | close(l.Setup) 154 | Dprintf("[L] Registered with banks and auditor\n") 155 | } 156 | 157 | // Bank reserving a spot in the ledger. Banks need to do this so they 158 | // know their transaction insertion point, and can generate proofs 159 | // accordingly with all the previous rows. 160 | func (l *Ledger) StartTxn(bank_i int, idx *int) error { 161 | Dprintf("[L] ---Checking setup %v...\n", bank_i) 162 | <-l.Setup 163 | Dprintf("[L] ---Received start txn from %v...\n", bank_i) 164 | l.mu.Lock() // Hold lock until transaction is processed 165 | l.start = time.Now() 166 | *idx = len(l.Transactions) 167 | Dprintf("[L][%v] Assigning txn ID...\n", *idx) 168 | return nil 169 | } 170 | 171 | // Bank submitting a transaction to the global ledger. The ledger adds 172 | // the transaction, and notifies everyone else so they can update 173 | // their local ledgers. 174 | func (l *Ledger) AppendTxn(etx *EncryptedTransaction, _ *struct{}) error { 175 | if *waitNotify { 176 | defer l.mu.Unlock() 177 | } 178 | Dprintf("[L][%v] Received txn ...\n", etx.Index) 179 | if len(l.Banks) == 0 { 180 | log.Panic("Need to set up the banks!") 181 | } 182 | if l.Auditor == nil { 183 | log.Panic("Need to set up the auditor!") 184 | } 185 | Dprintf("[L][%v] Processing new txn...\n", etx.Index) 186 | // TODO: verify, either here or in Append 187 | if etx.Index != len(l.Transactions) { 188 | log.Fatalf("[L] Out of order receive; my index %v, etx: %v\n", len(l.Transactions), etx.Index) 189 | } 190 | l.add(etx) 191 | if !*waitNotify { 192 | Dprintf("[L][%v] time holding mu %v ...\n", etx.Index, time.Since(l.start)) 193 | l.mu.Unlock() 194 | } 195 | if *parallelizeNotify { 196 | var wg sync.WaitGroup 197 | wg.Add(1 + l.num) 198 | go func() { 199 | if err := l.Auditor.Notify(etx, nil); err != nil { 200 | panic(err) 201 | } 202 | wg.Done() 203 | }() 204 | for i := 0; i < l.num; i++ { 205 | go func(i int) { 206 | if err := l.Banks[i].Notify(etx, nil); err != nil { 207 | panic(err) 208 | } 209 | wg.Done() 210 | }(i) 211 | } 212 | wg.Wait() 213 | } else { 214 | if err := l.Auditor.Notify(etx, nil); err != nil { 215 | panic(err) 216 | } 217 | for i := 0; i < l.num; i++ { 218 | if err := l.Banks[i].Notify(etx, nil); err != nil { 219 | panic(err) 220 | } 221 | } 222 | } 223 | Dprintf("[L][%v] time txn %v ...\n", etx.Index, time.Since(l.start)) 224 | return nil 225 | } 226 | -------------------------------------------------------------------------------- /ledger_test.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | ) 7 | 8 | func TestLocalLedger(t *testing.T) { 9 | l := MakeLocalLedger() 10 | etx := EncryptedTransaction{} 11 | idx := l.add(&etx) 12 | if idx != 0 { 13 | t.Errorf("Transaction added incorrectly %v\n", idx) 14 | } 15 | for i := 1; i < 10; i++ { 16 | idx := l.add(&etx) 17 | if idx != i { 18 | t.Errorf("Transaction added incorrectly %v\n", idx) 19 | } 20 | } 21 | fmt.Printf("Passed TestLocalLedger\n") 22 | } 23 | 24 | func TestLedger(t *testing.T) { 25 | l := MakeLedger(2) 26 | etx := EncryptedTransaction{} 27 | idx := l.add(&etx) 28 | if idx != 0 { 29 | t.Errorf("Transaction added incorrectly %v\n", idx) 30 | } 31 | for i := 1; i < 10; i++ { 32 | idx := l.add(&etx) 33 | if idx != i { 34 | t.Errorf("Transaction added incorrectly %v\n", idx) 35 | } 36 | } 37 | fmt.Printf("Passed TestLedger\n") 38 | } 39 | -------------------------------------------------------------------------------- /pki.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "errors" 5 | "io/ioutil" 6 | "math/big" 7 | "os" 8 | "path/filepath" 9 | "strconv" 10 | "strings" 11 | 12 | "github.com/mit-dci/zksigma" 13 | ) 14 | 15 | type PKI struct { 16 | PK []zksigma.ECPoint 17 | SK []*big.Int 18 | } 19 | 20 | func (p *PKI) Get(i int) zksigma.ECPoint { 21 | return p.PK[i] 22 | } 23 | 24 | func (p *PKI) GetSK(i int) *big.Int { 25 | return p.SK[i] 26 | } 27 | 28 | // n is the number of banks. We create n+1 keys for issuers 29 | func (p *PKI) MakeTest(n int) { 30 | p.PK = make([]zksigma.ECPoint, n+1) 31 | p.SK = make([]*big.Int, n+1) 32 | for i := 0; i < n+1; i++ { 33 | p.PK[i], p.SK[i] = zksigma.KeyGen(ZKLedgerCurve.C, ZKLedgerCurve.H) 34 | } 35 | // p.saveKeys() 36 | } 37 | 38 | func (p *PKI) MakeTestWithKeys(n int) { 39 | var err error 40 | p.PK, p.SK, err = p.loadPKI(n) 41 | check(err) 42 | } 43 | 44 | // load PKI takes in the number of banks in a system. Note that the issuer key is located at location n+1 45 | func (p *PKI) loadPKI(n int) ([]zksigma.ECPoint, []*big.Int, error) { 46 | pk := make([]zksigma.ECPoint, n+1) 47 | sk := make([]*big.Int, n+1) 48 | 49 | // get working directory 50 | cwd, err := filepath.Abs(filepath.Dir(os.Args[0])) 51 | check(err) 52 | // append folder directory and ensure it exists 53 | keyDirectory := filepath.Join(cwd, "keys") 54 | keyDirExists, err2 := exists(keyDirectory) 55 | check(err2) 56 | if !keyDirExists { 57 | return pk, sk, errors.New("** Key Directory not found: " + keyDirectory) 58 | } 59 | 60 | // iterate through files 61 | fileList := []string{} 62 | err = filepath.Walk(keyDirectory, func(path string, f os.FileInfo, err error) error { 63 | fileList = append(fileList, path) 64 | return nil 65 | }) 66 | check(err) 67 | 68 | keysFound := 0 // should be n+1 at the end 69 | 70 | for _, keyfile := range fileList { 71 | // expected file format: bi_pk or bi_sk or is_pk or is_sk where bi is bank i and 'is' is the issuer 72 | _, keyfileid := filepath.Split(keyfile) 73 | if keyfileid == "keys" { 74 | continue 75 | } 76 | content2 := strings.Split(keyfileid, "_") 77 | 78 | if content2[1] == "pk" { 79 | // time to load the public key 80 | filecontents, fileerr := ioutil.ReadFile(keyfile) // will read two integers separated by ',' 81 | check(fileerr) 82 | contentpk := strings.Split(string(filecontents), ",") 83 | pkX, success := new(big.Int).SetString(contentpk[0], 10) 84 | if !success { 85 | return pk, sk, errors.New("Issue parsing out X value of PK: " + contentpk[0]) 86 | } 87 | 88 | pkY, success := new(big.Int).SetString(contentpk[1], 10) 89 | if !success { 90 | return pk, sk, errors.New("Issue parsing out Y value of PK: " + contentpk[1]) 91 | } 92 | 93 | // set it to the correct role, either issuer or bank 94 | if content2[0] == "is" { 95 | pk[n] = zksigma.ECPoint{pkX, pkY} 96 | keysFound += 1 97 | } else { 98 | bankid, err := strconv.Atoi(content2[0][1:]) // since it is of the format 99 | check(err) 100 | if bankid >= n { // ignore any keys that are greater than ours 101 | continue 102 | } 103 | pk[bankid] = zksigma.ECPoint{pkX, pkY} 104 | keysFound += 1 105 | } 106 | } else if content2[1] == "sk" { // in real world setting there should only be 1 file 107 | filecontents, fileerr := ioutil.ReadFile(keyfile) 108 | check(fileerr) 109 | 110 | skval := new(big.Int).SetBytes(filecontents) 111 | 112 | if content2[0] == "is" { 113 | sk[n] = skval 114 | } else { 115 | bankid, err := strconv.Atoi(content2[0][1:]) // since it is of the format 116 | check(err) 117 | if bankid >= n { // ignore any keys that are greater than ours 118 | continue 119 | } 120 | sk[bankid] = skval 121 | } 122 | } 123 | } 124 | 125 | if keysFound != n+1 { 126 | Dprintf("Key files not found for all the banks! Dumping pk map: %v", pk) 127 | } 128 | 129 | return pk, sk, nil 130 | } 131 | 132 | func (p *PKI) saveKeys() { 133 | // get access to current working directory 134 | cwd, err := filepath.Abs(filepath.Dir(os.Args[0])) 135 | check(err) 136 | keyDirectory := filepath.Join(cwd, "keys") 137 | keyDirExists, err2 := exists(keyDirectory) 138 | check(err2) 139 | 140 | if !keyDirExists { 141 | os.Mkdir(keyDirectory, 0777) 142 | } 143 | 144 | // save the first n keys which are banks keys 145 | for i := 0; i < len(p.PK)-1; i++ { 146 | filenamePK := filepath.Join(keyDirectory, "b"+strconv.Itoa(i)+"_pk") 147 | filenameSK := filepath.Join(keyDirectory, "b"+strconv.Itoa(i)+"_sk") 148 | 149 | err = ioutil.WriteFile(filenamePK, []byte(p.PK[i].X.String()+","+p.PK[i].Y.String()), 0666) 150 | check(err) 151 | 152 | err = ioutil.WriteFile(filenameSK, p.SK[i].Bytes(), 0666) 153 | check(err) 154 | } 155 | 156 | filenamePK := filepath.Join(keyDirectory, "is_pk") 157 | filenameSK := filepath.Join(keyDirectory, "is_sk") 158 | 159 | err = ioutil.WriteFile(filenamePK, []byte(p.PK[len(p.PK)-1].X.String()+","+p.PK[len(p.PK)-1].Y.String()), 0666) 160 | check(err) 161 | 162 | err = ioutil.WriteFile(filenameSK, p.SK[len(p.PK)-1].Bytes(), 0666) 163 | check(err) 164 | 165 | } 166 | 167 | // exists returns whether the given file or directory exists or not 168 | func exists(path string) (bool, error) { 169 | _, err := os.Stat(path) 170 | if err == nil { 171 | return true, nil 172 | } 173 | if os.IsNotExist(err) { 174 | return false, nil 175 | } 176 | return true, err 177 | } 178 | -------------------------------------------------------------------------------- /testutil.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import "math/big" 4 | 5 | type System struct { 6 | L *Ledger 7 | B []*Bank 8 | A *Auditor 9 | } 10 | 11 | func SetupTest(n int, ntx int, initialAmount int64) System { 12 | pki := &PKI{} 13 | pki.MakeTest(n) 14 | ledger := MakeLedger(n) 15 | auditor := MakeAuditor(n, pki) 16 | ledger.Auditor = auditor 17 | banks := SetupLocalBanks(n, ledger, pki) 18 | ledger.Banks = make([]BankClient, n) 19 | auditor.banks = make([]BankClient, n) 20 | for i := 0; i < n; i++ { 21 | ledger.Banks[i] = banks[i] 22 | auditor.banks[i] = banks[i] 23 | close(banks[i].Setup) 24 | } 25 | close(ledger.Setup) 26 | close(auditor.Setup) 27 | s := System{ledger, banks, auditor} 28 | 29 | // issue out funds to each bank 30 | for i := 0; i < n; i++ { 31 | v := big.NewInt(initialAmount) 32 | banks[i].Issue(v, nil) // issue money 33 | } 34 | for i := 0; i < ntx; i++ { 35 | sender := i % n 36 | receiver := (i + 1) % n 37 | banks[sender].CreateEncryptedTransaction(receiver, big.NewInt(100)) 38 | } 39 | 40 | for i := 0; i < n; i++ { 41 | s.B[i].wait(ntx + n) 42 | } 43 | return s 44 | } 45 | 46 | func FinishTest(s System) { 47 | for i := 0; i < len(s.B); i++ { 48 | s.B[i].Stop(nil, nil) 49 | } 50 | s.A.Stop(nil, nil) 51 | } 52 | 53 | func StopWhen(s System, n int) { 54 | Dprintf("Setting wait to txn %v\n", n) 55 | for i := 0; i < len(s.B); i++ { 56 | s.B[i].When = n 57 | } 58 | } 59 | 60 | func Wait(s System) { 61 | for i := 0; i < len(s.B); i++ { 62 | <-s.B[i].Waiter 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /transaction.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "math/big" 7 | "runtime" 8 | "time" 9 | 10 | "github.com/mit-dci/zksigma" 11 | ) 12 | 13 | type TXN_TYPE int 14 | 15 | const ( 16 | Transfer TXN_TYPE = iota 17 | Issuance 18 | Withdrawal 19 | ) 20 | 21 | var parallelizeVerify = flag.Bool("pv", false, "Parallelize verification") 22 | var reduce = flag.Bool("re", false, "Reduce size of transactions by setting transaction proofs to nil after verification. Only works in distributed setting") 23 | 24 | type Entry struct { 25 | Bank int 26 | Comm zksigma.ECPoint // A_i 27 | RToken zksigma.ECPoint // B_i 28 | V *big.Int // unencrypted value for testing and issuance/withdrawal 29 | R *big.Int // value for testing 30 | CommAux zksigma.ECPoint // cm_{aux,i}, 31 | BAux zksigma.ECPoint // B_{aux,i} g^v*h^r' 32 | // Proof of well-formedness (r_i's match, v is 0 or I know sk) 33 | //WellFormed EquivORLogProof // "I know x st x = log_h(A_i) = log_{pk_i}(B_i) OR I know y st y = log_h(pk_i)" 34 | CommConsistency *zksigma.ConsistencyProof 35 | AuxConsistency *zksigma.ConsistencyProof 36 | Assets *zksigma.DisjunctiveProof // "cm_{aux,i}~\sum{cm_col} OR cm_{aux,i}~cm_i" 37 | RP *zksigma.RangeProof // cm_{aux,i} >= 0 38 | BAuxR *big.Int // Intermediately hold r here so I can generate the Range Proof outside of createLocal (holding the lock in ledger) 39 | SKProof *zksigma.GSPFSProof // Proof of knowledge of SK for issuance (issuer) or withdrawal (Bank) 40 | } 41 | 42 | // Well-formedness 43 | // --Proof that A_i and B_i are consistent (same r)-- 44 | // Proof that value is 0 for not-involved banks 45 | 46 | // Proof of assets 47 | // Proof that cm_{aux,i}~cm_i when v >= 0 48 | // Proof that cm_{aux_i}~\sum{cm_col} when v < 0 49 | // Range proof on cm_{aux,i} 50 | 51 | // New consistency proofs: 52 | // Proof that cm_i and B_i are consistent (same r) 53 | // Proof that cm_{aux,i} and B_{aux,i} are consistent (same r') 54 | 55 | type EncryptedTransaction struct { 56 | Index int `` 57 | TS time.Time 58 | Type TXN_TYPE 59 | Sender int // testing 60 | Receiver int // testing 61 | Entries []Entry 62 | skipVerify bool // Only for testing; default false 63 | } 64 | 65 | func (etx *EncryptedTransaction) reduce() { 66 | if *reduce { 67 | // Delete proofs 68 | for i := 0; i < len(etx.Entries); i++ { 69 | e := &etx.Entries[i] 70 | e.CommConsistency = nil 71 | e.AuxConsistency = nil 72 | e.Assets = nil 73 | e.RP = nil 74 | e.SKProof = nil 75 | } 76 | } 77 | } 78 | 79 | // Only for testing 80 | func (e *EncryptedTransaction) print_decrypted() { 81 | Dprintf("ETX %v\t{", e.Index) 82 | for i := 0; i < len(e.Entries); i++ { 83 | ent := &e.Entries[i] 84 | Dprintf("b%v :[%#v] \n", i, ent) 85 | } 86 | Dprintf("}\n") 87 | } 88 | 89 | func (en *Entry) verify(pks []zksigma.ECPoint, CommCache zksigma.ECPoint, RTokenCache zksigma.ECPoint, eidx int, i int, debug string) bool { 90 | // Check consistency proofs 91 | ok, err := en.CommConsistency.Verify(ZKLedgerCurve, en.Comm, en.RToken, pks[i]) 92 | if !ok { 93 | Dprintf(" [%v] ETX %v Failed verify consistency comm entry %v %#v\n", debug, eidx, i, en) 94 | Dprintf(" [%v] %s", debug, err.Error()) 95 | return false 96 | } 97 | ok, err = en.AuxConsistency.Verify(ZKLedgerCurve, en.CommAux, en.BAux, pks[i]) 98 | if !ok { 99 | Dprintf(" [%v] ETX %v Failed verify consistency aux entry %v\n", debug, eidx, i) 100 | Dprintf(" [%v] %s", debug, err.Error()) 101 | return false 102 | } 103 | // Check Proof of Assets 104 | Base1 := ZKLedgerCurve.Add(en.CommAux, ZKLedgerCurve.Neg(ZKLedgerCurve.Add(CommCache, en.Comm))) 105 | Result1 := ZKLedgerCurve.Add(en.BAux, ZKLedgerCurve.Neg(ZKLedgerCurve.Add(RTokenCache, en.RToken))) 106 | Result2 := ZKLedgerCurve.Add(en.CommAux, ZKLedgerCurve.Neg(en.Comm)) 107 | ok, err = en.Assets.Verify(ZKLedgerCurve, Base1, Result1, ZKLedgerCurve.H, Result2) 108 | if !ok { 109 | fmt.Printf(" [%v] %v/%v Base1: %v\n", debug, eidx, i, Base1) 110 | fmt.Printf(" [%v] %v/%v Result1: %v\n", debug, eidx, i, Result1) 111 | fmt.Printf(" [%v] %v/%v Result2: %v\n", debug, eidx, i, Result2) 112 | fmt.Printf(" [%v] ETX %v Failed verify left side of proof of assets entry %v\n", debug, eidx, i) 113 | fmt.Printf(" [%v] %s", debug, err.Error()) 114 | return false 115 | } 116 | // Range Proof 117 | ok, err = en.RP.Verify(ZKLedgerCurve, en.CommAux) 118 | if !ok { 119 | Dprintf(" [%v] %v/%v Range Proof: %v\n", debug, eidx, i, en.RP) 120 | Dprintf(" [%v] ETX %v Failed verify the range proof on CommAux %v\n", debug, eidx, i) 121 | Dprintf(" [%v] %s", debug, err.Error()) 122 | return false 123 | } 124 | return true 125 | } 126 | 127 | func (e *EncryptedTransaction) Verify(pks []zksigma.ECPoint, CommCache []zksigma.ECPoint, RTokenCache []zksigma.ECPoint, debug string) bool { 128 | if e.skipVerify { 129 | return true 130 | } 131 | // Issuance 132 | if e.Type == Issuance { 133 | en := &e.Entries[e.Sender] 134 | if en.V.Cmp(big.NewInt(0)) <= 0 { 135 | Dprintf(" [%v] ETX %v Failed verify; issuance transaction values must be positive\n", 136 | debug, e.Index) 137 | return false 138 | } 139 | // Check proof of knowledge of sk_{asset issuer} 140 | ok := false 141 | if en.SKProof != nil { 142 | // TODO: Error handling 143 | ok, _ = en.SKProof.Verify(ZKLedgerCurve, pks[len(pks)-1]) 144 | } 145 | if !ok { 146 | Dprintf("[%v] ETX %v Failed issuance: proof of knowledge of SK\n", debug, e.Index) 147 | return false 148 | } 149 | return true 150 | } 151 | // Withdrawal 152 | if e.Type == Withdrawal { 153 | en := &e.Entries[e.Sender] 154 | if en.V.Cmp(big.NewInt(0)) > 0 { 155 | Dprintf(" [%v] ETX %v Failed verify; withdrawal transaction values must be negative\n", 156 | debug, e.Index) 157 | return false 158 | } 159 | // Check proof of knowledge of sk_{bank} 160 | // TODO: Error handling 161 | ok, _ := en.SKProof.Verify(ZKLedgerCurve, pks[e.Sender]) 162 | if !ok { 163 | Dprintf(" [%v] ETX %v Failed withdrawal: proof of knowledge of SK\n", debug, e.Index) 164 | return false 165 | } 166 | return true 167 | } 168 | // Transfer 169 | 170 | if (len(pks) - 1) != len(e.Entries) { // we subtract 1 from len(pks) because the last entry is the issuer's key 171 | fmt.Printf("Length pks: %v, length entries: %v\n", len(pks)-1, len(e.Entries)) 172 | panic("invalid sizes") 173 | } 174 | commitmentSum := zksigma.Zero 175 | rets := make(chan bool) 176 | for i := 0; i < len(e.Entries); i++ { 177 | en := &e.Entries[i] 178 | commitmentSum = ZKLedgerCurve.Add(commitmentSum, en.Comm) 179 | if en.Bank != i { 180 | Dprintf(" [%v] ETX %v Failed verify mismatching bank %#v\n", debug, e.Index, en) 181 | return false 182 | } 183 | if *parallelizeVerify && runtime.NumCPU() > 1 { 184 | go func(i int) { 185 | x := en.verify(pks, CommCache[i], RTokenCache[i], e.Index, i, debug) 186 | if x != true { 187 | fmt.Printf("[%v] ETX %v Failed entry verification; %v spending %v receiving %v amt\n", debug, e.Index, e.Sender, e.Receiver, e.Entries[e.Sender].V) 188 | } 189 | rets <- x 190 | }(i) 191 | } else { 192 | if !en.verify(pks, CommCache[i], RTokenCache[i], e.Index, i, debug) { 193 | return false 194 | } 195 | } 196 | } 197 | if *parallelizeVerify && runtime.NumCPU() > 1 { 198 | success := true 199 | for i := 0; i < len(e.Entries); i++ { 200 | if r := <-rets; !r { 201 | success = false 202 | } 203 | } 204 | close(rets) 205 | if !success { 206 | return false 207 | } 208 | } 209 | 210 | // to verify the zero sum commitments we add up all the values and make sure it adds to 0 211 | /* 212 | if !VerifyZeroSumCommitments(*e, gsp) { 213 | Dprintf(" [%v] ETX %v Failed verify zero sum\n", debug, e.Index) 214 | return false 215 | }*/ 216 | if commitmentSum.X.Cmp(new(big.Int).SetInt64(0)) != 0 && commitmentSum.Y.Cmp(new(big.Int).SetInt64(0)) != 0 { 217 | Dprintf(" [%v] ETX %v Failed verify zero sum\n", debug, e.Index) 218 | return false 219 | } 220 | 221 | return true 222 | } 223 | -------------------------------------------------------------------------------- /zkcurve.go: -------------------------------------------------------------------------------- 1 | package zkledger 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/binary" 6 | "math/big" 7 | 8 | "github.com/mit-dci/zksigma" 9 | "github.com/mit-dci/zksigma/btcec" 10 | ) 11 | 12 | // ZKLedgerCurve is a global cache for the curve and two generator points used in the various proof 13 | // generation and verification functions. 14 | var ZKLedgerCurve zksigma.ZKPCurveParams 15 | 16 | func generateH2tothe() []zksigma.ECPoint { 17 | Hslice := make([]zksigma.ECPoint, 64) 18 | for i := range Hslice { 19 | m := big.NewInt(1 << uint(i)) 20 | Hslice[i].X, Hslice[i].Y = ZKLedgerCurve.C.ScalarBaseMult(m.Bytes()) 21 | } 22 | return Hslice 23 | } 24 | 25 | func init() { 26 | s256 := sha256.New() 27 | 28 | // This was changed in ZKSigma, but keys already generated part of the repo 29 | // should still work. So reverted this to what was originally in ZKLedger, 30 | 31 | // see: 32 | // hashedString := s256.Sum([]byte("This is the new random point in zksigma")) 33 | // HX, HY := btcec.S256().ScalarMult(btcec.S256().Gx, btcec.S256().Gy, hashedString) 34 | curValue := btcec.S256().Gx 35 | s256.Write(new(big.Int).Add(curValue, big.NewInt(2)).Bytes()) // hash G_x + 2 which 36 | 37 | potentialXValue := make([]byte, 33) 38 | binary.LittleEndian.PutUint32(potentialXValue, 2) 39 | for i, elem := range s256.Sum(nil) { 40 | potentialXValue[i+1] = elem 41 | } 42 | 43 | H, err := btcec.ParsePubKey(potentialXValue, btcec.S256()) 44 | if err != nil { 45 | panic(err) 46 | } 47 | ZKLedgerCurve = zksigma.ZKPCurveParams{ 48 | C: btcec.S256(), 49 | G: zksigma.ECPoint{btcec.S256().Gx, btcec.S256().Gy}, 50 | H: zksigma.ECPoint{H.X, H.Y}, 51 | } 52 | ZKLedgerCurve.HPoints = generateH2tothe() 53 | } 54 | -------------------------------------------------------------------------------- /zkledger.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mit-dci/zkledger/a7f074c7e62f2fcb469628558b90274c31ea570c/zkledger.pdf --------------------------------------------------------------------------------