Commits

Eric Roshan Eisner committed 255e9c7 Draft

change apply and readState to fit the sponge metaphor

  • Participants
  • Parent commits 5d253ce

Comments (0)

Files changed (1)

 	// buf[:n] holds buffered data awaiting a full block (n < blocksize)
 	buf [200]byte
 	n   int
+	// closed is set when this is closed for writing.
+	closed bool
 }
 
 func newSHA3(bitsize int) *keccak {
 		d.buf[i] = 0
 	}
 	d.n = 0
+	d.closed = false
 }
 
-// apply accepts a block of data with len exactly d.blocksize. It
-// xor's this data to the front of d.state (little endian), then performs
-// one KeccakF[1600] permutation.
-func (d *keccak) apply(chunk []byte) {
-	for i := 0; i < len(chunk); i += 8 {
+// The internal state should be written to then read with calls to absorb,
+// then exactly one call to pad, then calls to squeeze.
+
+// absorb accepts a block of data with len exactly d.blocksize. It xor's this
+// data to the front of d.state (little endian), then performs one
+// KeccakF[1600] permutation.
+func (d *keccak) absorb(chunk []byte) {
+	for i := 0; i < d.blocksize; i += 8 {
 		d.state[i/8] ^= readLane(chunk[i : i+8])
 	}
 	block(&d.state)
 }
 
-// readState reads the first block of data from the state to the buf
-func (d *keccak) readState() {
+// pad fills the remaining bytes in the block with the 10*1 padding rule, then
+// writes it out to the state.
+func (d *keccak) pad() {
+	if d.closed {
+		panic("sha3: close after close")
+	}
+	d.buf[d.n] = 0x01
+	for i := d.n + 1; i < len(d.buf); i++ {
+		d.buf[i] = 0
+	}
+	d.buf[d.blocksize-1] |= 0x80
+
+	for i := 0; i < d.blocksize; i += 8 {
+		d.state[i/8] ^= readLane(d.buf[i : i+8])
+	}
+	d.closed = true
+}
+
+// squeeze performs the permutation to the state, then reads the first block
+// of data from the state (little endian) to buf
+func (d *keccak) squeeze() {
+	if !d.closed {
+		panic("sha3: Read before close")
+	}
+	block(&d.state)
 	for i := 0; i < d.blocksize; i += 8 {
 		writeLane(d.buf[i:i+8], d.state[i/8])
 	}
 	d.n = 0
 }
 
-// Write uses d.buf to buffer calls to d.apply from arbitrary sized inputs.
+// Write uses d.buf to buffer calls to d.absorb from arbitrary sized inputs.
 func (d *keccak) Write(b []byte) (nn int, err error) {
+	if d.closed {
+		panic("sha3: Write after close")
+	}
 	nn = len(b)
 	if d.n > 0 {
 		// Add to buffer.
 			return
 		} else {
 			copy(d.buf[d.n:d.blocksize], b)
-			d.apply(d.buf[:d.blocksize])
+			d.absorb(d.buf[:d.blocksize])
 			b = b[d.blocksize-d.n:]
 			d.n = 0
 		}
 	}
 
 	for len(b) >= d.blocksize {
-		d.apply(b[:d.blocksize])
+		d.absorb(b[:d.blocksize])
 		b = b[d.blocksize:]
 	}
 
 	return
 }
 
-func (d *keccak) pad() {
-	// Pad remaining bytes in block with 10*1 padding rule
-	d.buf[d.n] = 0x01
-	for i := d.n + 1; i < len(d.buf); i++ {
-		d.buf[i] = 0
-	}
-	d.buf[d.blocksize-1] |= 0x80
-
-	d.apply(d.buf[:d.blocksize])
-}
-
 func (d0 *keccak) Sum(in []byte) []byte {
 	// Work on a copy to keep the original unmodified.
 	d := *d0
 	d.pad()
-	d.readState()
+	d.squeeze()
 	return append(in, d.buf[:d.size]...)
 }