如何同时返回一个处理过的列表和一个修改过的对象?

huangapple go评论81阅读模式
英文:

How do I return both a processed list and a modified object?

问题

我正在设计一个名为Daphne的密码系统,它接受一个字节的明文并返回一个加密的字节和一个修改后的Daphne。当应用于一个列表时,它应该返回加密字节的列表以及处理所有字节后的Daphne。我不确定如何在不占用O(n)内存的情况下完成这个任务。以下是代码:

byteEncrypt :: Daphne -> Word8 -> (Daphne,Word8)
byteEncrypt (Daphne key sreg acc) plain = ((Daphne key newsreg newacc),crypt) where
  left = computeLeft key sreg acc
  right = computeRight key sreg acc
  crypt = step plain left right
  newacc = acc+plain
  newsreg = Seq.drop 1 (sreg |> crypt)

byteDecrypt :: Daphne -> Word8 -> (Daphne,Word8)
byteDecrypt (Daphne key sreg acc) crypt = ((Daphne key newsreg newacc),plain) where
  left = computeLeft key sreg acc
  right = computeRight key sreg acc
  plain = invStep crypt left right
  newacc = acc+plain
  newsreg = Seq.drop 1 (sreg |> crypt)

seqEncrypt :: Seq.Seq Word8 -> (Daphne,Seq.Seq Word8) -> (Daphne,Seq.Seq Word8)
seqEncrypt Seq.Empty a = a
seqEncrypt (bs:|>b) (daph,acc) = (daph2,acc2) where
  (daph1,acc1) = seqEncrypt bs (daph,acc)
  (daph2,c) = byteEncrypt daph1 b
  acc2 = acc1 |> c

listEncrypt :: Daphne -> [Word8] -> (Daphne,[Word8])
listEncrypt daph bs = (daph1,toList seq1) where
  (daph1,seq1) = seqEncrypt (Seq.fromList bs) (daph,Seq.Empty)

seqDecrypt :: Seq.Seq Word8 -> (Daphne,Seq.Seq Word8) -> (Daphne,Seq.Seq Word8)
seqDecrypt Seq.Empty a = a
seqDecrypt (bs:|>b) (daph,acc) = (daph2,acc2) where
  (daph1,acc1) = seqDecrypt bs (daph,acc)
  (daph2,c) = byteDecrypt daph1 b
  acc2 = acc1 |> c

listDecrypt :: Daphne -> [Word8] -> (Daphne,[Word8])
listDecrypt daph bs = (daph1,toList seq1) where
  (daph1,seq1) = seqDecrypt (Seq.fromList bs) (daph,Seq.Empty)

listEncrypt 在RAM中有列表的副本作为序列,占用了O(n)的内存,这是不必要的。

完整的代码可以在https://github.com/phma/daphne 中找到。它还没有准备好用于生产;我还没有进行密码分析,其他人也没有。我可能会运行大量数据并计算统计信息。

英文:

I'm designing a cipher called Daphne, which takes a byte of plaintext and returns an encrypted byte and a modified Daphne. When applied to a list, it should return the list of encrypted bytes and the Daphne after it has processed all the bytes. I'm not sure how to do this without taking O(n) memory. Here's the code:

byteEncrypt :: Daphne -> Word8 -> (Daphne,Word8)
byteEncrypt (Daphne key sreg acc) plain = ((Daphne key newsreg newacc),crypt) where
left = computeLeft key sreg acc
right = computeRight key sreg acc
crypt = step plain left right
newacc = acc+plain
newsreg = Seq.drop 1 (sreg |> crypt)
byteDecrypt :: Daphne -> Word8 -> (Daphne,Word8)
byteDecrypt (Daphne key sreg acc) crypt = ((Daphne key newsreg newacc),plain) where
left = computeLeft key sreg acc
right = computeRight key sreg acc
plain = invStep crypt left right
newacc = acc+plain
newsreg = Seq.drop 1 (sreg |> crypt)
seqEncrypt :: Seq.Seq Word8 -> (Daphne,Seq.Seq Word8) -> (Daphne,Seq.Seq Word8)
seqEncrypt Seq.Empty a = a
seqEncrypt (bs:|>b) (daph,acc) = (daph2,acc2) where
(daph1,acc1) = seqEncrypt bs (daph,acc)
(daph2,c) = byteEncrypt daph1 b
acc2 = acc1 |> c
listEncrypt :: Daphne -> [Word8] -> (Daphne,[Word8])
listEncrypt daph bs = (daph1,toList seq1) where
(daph1,seq1) = seqEncrypt (Seq.fromList bs) (daph,Seq.Empty)
seqDecrypt :: Seq.Seq Word8 -> (Daphne,Seq.Seq Word8) -> (Daphne,Seq.Seq Word8)
seqDecrypt Seq.Empty a = a
seqDecrypt (bs:|>b) (daph,acc) = (daph2,acc2) where
(daph1,acc1) = seqDecrypt bs (daph,acc)
(daph2,c) = byteDecrypt daph1 b
acc2 = acc1 |> c
listDecrypt :: Daphne -> [Word8] -> (Daphne,[Word8])
listDecrypt daph bs = (daph1,toList seq1) where
(daph1,seq1) = seqDecrypt (Seq.fromList bs) (daph,Seq.Empty)

listEncrypt has a copy of the list in RAM as a sequence, which takes up O(n) RAM, which shouldn't be necessary.

The full code is at https://github.com/phma/daphne . It's not ready for production yet; I haven't cryptanalyzed it, let alone anyone else. I may run gigabytes of data through it and compute statistics.

答案1

得分: 1

我还没有真正理解为什么你引入了序列,所以我可能误解了问题。但似乎在列表上递归会很好用。类似这样(未经测试):

listEncrypt daph [] = (daph, [])
listEncrypt daph (b:bs) = (finalDaph, e:es)
  where
    (nextDaph, e) = byteEncrypt daph b
    (finalDaph, es) = listEncrypt nextDaph bs

实际上,这个模式实际上是 [mapAccumL][1]。我认为 byteEncrypt 已经按正确的顺序接受了其参数,所以它只需这样:

listEncrypt = mapAccumL byteEncrypt

这两者只需要恒定的内存,但有一个注意事项。如果在使用加密列表之前检查最终的 Daphne,例如通过执行 print (listEncrypt something something),它将不得不遍历整个列表以首先获取最终的 Daphne,同时将整个加密列表保留在内存中以便后续使用。首先打印加密列表,然后再打印最终的 Daphne,应该没问题。如果只检查 snd (listEncrypt something something),它甚至可以在无限列表上工作。

英文:

I haven't really understood why you introduced sequences at all, so I
may have misunderstood the problem. But it seems like recursing on
the list would work fine. Something like (untested)

listEncrypt daph [] = (daph, [])
listEncrypt daph (b:bs) = (finalDaph, e:es)
where
(nextDaph, e) = byteEncrypt daph b
(finalDaph, es) = listEncrypt nextDaph bs

And actually this pattern is a mapAccumL. I think byteEncrypt already has its arguments in the right order so it would just be

listEncrypt = mapAccumL byteEncrypt

Either of these should only need constant memory, but with one caveat.
If you inspect the final daphne before using the encrypted list, for
example by doing print (listEncrypt something something), it will
have to go through the whole list to get the final daphne first while
keeping the whole encrypted list in memory to be able to use that
next. Print the encrypted list first and then the final daphne and
it should be fine. And if you only inspect snd (listEncrypt
something something)
it should work even on infinite lists.

huangapple
  • 本文由 发表于 2023年7月3日 16:47:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76603192.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定