Signature RedactionWith a redactable signaure, we can removed elements of the data and still create a valid signature that can be checked. For the example below, the message is "Dear Alice. This is my contact to you, and I believe this is correct". We will produce a signature for each of the words, and then redact the first two words, and regenerate a redacted signature: |
Method
With a naive redacted signature, the message is split into partitions (such as seperated by spaces). We can then just sign each of the partitions, and where each partition has a count identifier. In the following we have a message (\(m\) and which has \(n\) partitions:
\(Sig=Sig(H(n || ID)) || Sig(H(ID || 0 || m_0)) || ... || Sig(H(ID || n || m_n))\)
Coding
The following is the Golang code (based on code]):
// Code based on https://github.com/Romern/redactionschemes package main import ( "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "fmt" "strings" "os" "encoding/json" "github.com/Romern/redactionschemes" ) func SplitIntoWords(s string) *redactionschemes.PartitionedData { var out redactionschemes.PartitionedData for _, v := range strings.Split(s, " ") { out = append(out, []byte(string(v))) } return &out } func main() { input_string := "This is a test" argCount := len(os.Args[1:]) if argCount > 0 { input_string = string(os.Args[1]) } private_key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) var sig redactionschemes.NaiveSignature var priv crypto.PrivateKey = private_key fmt.Printf("Private key: %s\n", private_key.D) fmt.Printf("Public key: %s, %s\n", private_key.X, private_key.Y) data_input := SplitIntoWords(input_string) incorrect_data := SplitIntoWords(input_string + "incorrect!") redacted_data := []int{0, 1} // Remove first and second word fmt.Printf("\nData input: %s\n", input_string) fmt.Printf("Data input: %v\n", data_input) fmt.Printf("Redacted data: %v\n", redacted_data) err := sig.Sign(data_input, &priv) if err == nil { // sig_marshaled, _ := sig.Marshal() fmt.Printf("\nSuccessful signing %x\n", sig.BaseSignature) err = sig.Verify(data_input) if err == nil { fmt.Printf("Successful Verification\n") } } newSig, _ := sig.Redact(redacted_data, data_input) if err == nil { r, _ := newSig.Marshal() var v map[string]string _ = json.Unmarshal([]byte(r), &v) fmt.Printf("\nSuccessful redaction %x\n", v["BaseSignature"]) redacted_strings, _ := data_input.Redact(redacted_data) err = newSig.Verify(redacted_strings) if err == nil { fmt.Printf("Successful Redaction\n") } err = sig.Verify(incorrect_data) if err != nil { fmt.Printf("Successful Checking against incorrect data\n") } } }
And a sample run with the removal of the first and second word is::
Private key: 77431666133203016720299350435698111186118376456137320936654008639278326685538 Public key: 87893687952680097626094882734089745596691483788507209590673819347587073650364, 63425867996608024706944022962559021886975544239946733267473759044983582729429 Data input: Dear Alice. This is my contract to you, and I believe this is correct. Data input: .[[68 101 97 114] [65 108 105 99 101 46] [84 104 105 115] [105 115] [109 121] [99 111 110 116 114 97 99 116] [116 111] [121 111 117 44] [97 110 100] [73] [98 101 108 105 101 118 101] [116 104 105 115] [105 115] [99 111 114 114 101 99 116 46]] Redacted data: [0 1] Successful signing 3046022100974e49f309ab864bf4ec706b5d118443c2847fa8098e2c036bddedea0e3a21e202210098156529cad277ac70664fb12d460d517419a0f04e409cfec0f2c08e8d54b497 Successful Verification Successful redaction 4d45594349514358546b6e7a43617547532f54736347746445595244776f522f71416d4f4c414e7233653371446a6f6834674968414a67565a536e4b306e657363475a50735331474456463047614477546b43632f7344797749364e564c5358 Successful Redaction Successful Checking against incorrect data