Commit 64f34bc
Changed files (10)
go-code
hello
ltcodes
ltdemo
string
go-code/hello/hello.go
@@ -0,0 +1,9 @@
+package main
+
+import (
+ "fmt"
+ "github.com/bryfry/string"
+)
+func main() {
+ fmt.Println(string.Reverse("Hello, World!"))
+}
go-code/ltcodes/.ltcodes.go.swp
Binary file
go-code/ltcodes/ltcodes.go
@@ -0,0 +1,186 @@
+package ltcodes
+
+import "math/rand"
+import "fmt"
+import "math"
+import "bytes"
+
+type Packet struct {
+ n int
+ degree int
+ seed int64
+ data []byte
+}
+
+type indexedPacket struct {
+ index []int
+ degree int
+ data []byte
+}
+
+func xorBytes(b ...[]byte) []byte {
+ b_len := len(b[0])
+ for _, m := range b {
+ if len(m) != b_len {
+ panic("length mismatch!")
+ }
+ }
+ br := make([]byte, b_len)
+ for i := range b[0] {
+ br[i] = 0
+ for _, m := range b {
+ br[i] = br[i] ^ m[i]
+ }
+ }
+ return br
+}
+
+func degreeGen(msg_len int, block_len int) int {
+ // returns 1 <= d <= msg_len - block_len
+ // TODO: implement "robust soliton distribution" here
+ return rand.Intn(msg_len-block_len-1) + 1
+}
+
+// create or reconstruct the list of source blocks that were used
+// to generate an encoded block
+func indexGen(degree int, seed int64, n_blocks int) []int {
+ psudo_seed := rand.NewSource(seed)
+ psudo_rng := rand.New(psudo_seed)
+ indices := make([]int, degree)
+ for i := 0; i < degree; i++ {
+ indices[i] = psudo_rng.Intn(n_blocks)
+ }
+ return indices
+}
+
+// Emit one encoded Packet from message msg and of length block_len
+// Packet return includes: generated degree (degree), index seed (seed),
+// number of blocks msg has been divided into (n), and the encoded data (data)
+func Encode(packets chan<- Packet, msg []byte, block_len int) Packet {
+ for {
+ // TODO: add check for erroneous block_len (relative to len(m))
+ n_blocks := len(msg) / block_len
+ degree := degreeGen(len(msg), block_len)
+ blocks := make([][]byte, degree)
+ seed := rand.Int63n(math.MaxInt64)
+ indices := indexGen(degree, seed, n_blocks)
+ for i, m := range indices {
+ blocks[i] = make([]byte, block_len)
+ blocks[i] = msg[m*block_len : (m*block_len + block_len)]
+ }
+ packets <- Packet{n: n_blocks, degree: degree, seed: seed, data: xorBytes(blocks...)}
+ }
+}
+
+// check if decoding complete
+func messageDecoded(message [][]byte) bool {
+ for _, v := range message {
+ if v == nil {
+ return false
+ }
+ }
+ return true
+}
+
+// translation from packet to indexedPacket type
+func indexPacket(p Packet) indexedPacket {
+ i := indexGen(p.degree, p.seed, p.n)
+ return indexedPacket{index: i, degree: p.degree, data: p.data}
+}
+
+// decrease the index of "packet" at index "i" by xoring in "clean_data"
+// return updated packet
+func reducePacket(i int, packet indexedPacket, clean_data []byte) indexedPacket {
+ packet.data = xorBytes(packet.data, clean_data)
+ packet.index = append(packet.index[:i], packet.index[i+1:]...)
+ packet.degree = packet.degree - 1
+ return packet
+}
+
+// check packet for index values that match up with clean ones (stored in message)
+// reduce packet if match found and return it
+func process(packet indexedPacket, message [][]byte) indexedPacket {
+ for i := 0; i < len(packet.index); i++ { //, m_i := range packet.index {
+ if message[packet.index[i]] != nil {
+ packet = reducePacket(i, packet, message[packet.index[i]])
+ }
+ }
+ return packet
+}
+
+// check clean data against buffer of unprocessed data
+func processClean(clean indexedPacket, buffer_area []indexedPacket, message [][]byte) ([][]byte, []indexedPacket) {
+ if len(clean.index) != 1 {
+ panic("received 'clean' of degree != 1")
+ }
+ clean_index := clean.index[0]
+ message[clean_index] = clean.data
+ if messageDecoded(message) {
+ return message, buffer_area
+ }
+
+ // loop over all buffered packets
+ for b_i := 0; b_i < len(buffer_area); b_i++ {
+ packet := buffer_area[b_i]
+
+ // loop over packet index
+ for i := 0; i < len(packet.index); i++ {
+
+ // if match, reduce packet
+ if clean_index == packet.index[i] {
+
+ // important to update packet (for loop needs it)
+ packet = reducePacket(i, packet, clean.data)
+ buffer_area[b_i] = packet
+
+ // check for and handle a new clean packet
+ if packet.degree == 1 {
+ buffer_area = append(buffer_area[:b_i], buffer_area[b_i+1:]...)
+ if message[packet.index[0]] == nil {
+ message, buffer_area = processClean(packet, buffer_area, message)
+ }
+ }
+ }
+ }
+ }
+ return message, buffer_area
+}
+
+// receive packets and combine them until message discovered
+func Decode(packets <-chan Packet, decodeDone chan<- bool) {
+
+ // get first packet and setup
+ p := <-packets
+ message := make([][]byte, p.n)
+ buffer_area := make([]indexedPacket, 1)
+ buffer_area[0] = indexPacket(p)
+ counter := 0
+
+ // packet receive loop
+ for {
+ p := indexPacket(<-packets)
+ counter++
+
+ if p.degree > 1 {
+ p = process(p, message)
+
+ if p.degree > 1 {
+ buffer_area = append(buffer_area, p)
+
+ } else if p.degree == 1 {
+ message, buffer_area = processClean(p, buffer_area, message)
+ }
+
+ } else if p.degree == 1 {
+ message, buffer_area = processClean(p, buffer_area, message)
+ }
+
+ if messageDecoded(message) {
+ fmt.Println("Packets:", counter)
+ outMsg := bytes.Join(message, []byte{})
+ fmt.Println("Packets / byte:", float64(counter)/float64(len(outMsg)))
+ decodeDone <- true
+ return
+ }
+ }
+}
go-code/ltdemo/.ltdemo.go.swp
Binary file
go-code/ltdemo/ltdemo
Binary file
go-code/ltdemo/ltdemo.go
@@ -0,0 +1,50 @@
+package main
+
+//import "encoding/hex"
+//import "math"
+import "github.com/bryfry/ltcodes"
+import "math/rand"
+import "fmt"
+import "time"
+
+func main() {
+ rand.Seed(time.Now().UTC().UnixNano())
+ block_len := 15
+ test_msg := []byte("this is a test, this is only a test. Drop the beat!")
+ //fmt.Println(test_msg)
+ packets := make(chan ltcodes.Packet, 100)
+ decodeDone := make(chan bool)
+
+ // emit packets
+ go ltcodes.Encode(packets, test_msg, block_len)
+ go ltcodes.Decode(packets, decodeDone)
+ for {
+ select {
+ case <-decodeDone:
+ fmt.Println("Decode complete!")
+ return
+ }
+ }
+ close(packets)
+
+ // move to test
+ /*debug_xor := false
+ if debug_xor {
+ b1 := []byte("WhatAmIDoingHere?")
+ b2 := []byte("thisisjustatest !")
+ b3 := []byte("omg, there's more")
+ fmt.Println(hex.EncodeToString(xorBytes(b1, b2, b1, b2)))
+ fmt.Println(hex.EncodeToString([]byte(b1)))
+ fmt.Println(hex.EncodeToString(xorBytes(b1, b2, b3)))
+ fmt.Println(hex.EncodeToString(xorBytes(b1, b1))) // expect all 00's
+ fmt.Println(string(xorBytes(b1, b2, b1))[:len(b1)]) // expect b2
+ b123 := [][]byte{b1, b2, b3}
+ b11 := [][]byte{b1, b1}
+ b121 := [][]byte{b1, b2, b1}
+ b1only := [][]byte{b1}
+ fmt.Println(hex.EncodeToString(xorBytes(b123...))) // expect same an non 2d slice array
+ fmt.Println(hex.EncodeToString(xorBytes(b11...))) // expect all 00's
+ fmt.Println(string(xorBytes(b121...))[:len(b1)]) // expect b2
+ fmt.Println(string(xorBytes(b1only...))[:len(b1)]) // expect b1
+ }*/
+}
go-code/string/string.go
@@ -0,0 +1,10 @@
+package string
+
+func Reverse(s string) string {
+ b := []rune(s)
+ for i:=0; i<len(b)/2; i++ {
+ j := len(b)-i-1
+ b[i], b[j] = b[j], b[i]
+ }
+ return string(b)
+}
go-code/string/string_test.go
@@ -0,0 +1,19 @@
+package string
+
+import "testing"
+
+func Test(t *testing.T) {
+ var tests = []struct {
+ s, want string
+ }{
+ {"Backward", "drawkcaB"},
+ {"I am dissapoint ಠ_ಠ","ಠ_ಠ tniopassid ma I"},
+ {"",""},
+ }
+ for _, c := range tests {
+ got := Reverse(c.s)
+ if got != c.want {
+ t.Errorf("Reverse(%q) == %q, want %q", c.s, got, c.want)
+ }
+ }
+}
go-code/.gitignore
@@ -0,0 +1,1 @@
+.DS_Store
go-code/README.md
@@ -0,0 +1,4 @@
+go-code
+=======
+
+playground for go code