technical doc: add a design doc for hash function transition
This document describes what a transition to a new hash function for Git would look like. Add it to Documentation/technical/ as the plan of record so that future changes can be recorded as patches. Also-by: Brandon Williams <bmwill@google.com> Also-by: Jonathan Tan <jonathantanmy@google.com> Also-by: Stefan Beller <sbeller@google.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jonathan Nieder committed
Sep 27, 2017 at 21:43 UTC
752414ae4310cd304f5e31649aaab2dcf307057c
2 files changed
+798
Documentation/Makefile
+1
@@ -67,6 +67,7 @@ SP_ARTICLES += howto/maintain-git
67
API_DOCS = $(patsubst %.txt,%,$(filter-out technical/api-index-skel.txt technical/api-index.txt, $(wildcard technical/api-*.txt)))
68
SP_ARTICLES += $(API_DOCS)
69
70
+TECH_DOCS += technical/hash-function-transition
71
TECH_DOCS += technical/http-protocol
72
TECH_DOCS += technical/index-format
73
TECH_DOCS += technical/pack-format
Documentation/technical/hash-function-transition.txt
new
+797
@@ -0,0 +1,797 @@
1
+Git hash function transition
2
+============================
3
+
4
+Objective
5
+---------
6
+Migrate Git from SHA-1 to a stronger hash function.
7
+
8
+Background
9
+----------
10
+At its core, the Git version control system is a content addressable
11
+filesystem. It uses the SHA-1 hash function to name content. For
12
+example, files, directories, and revisions are referred to by hash
13
+values unlike in other traditional version control systems where files
14
+or versions are referred to via sequential numbers. The use of a hash
15
+function to address its content delivers a few advantages:
16
+
17
+* Integrity checking is easy. Bit flips, for example, are easily
18
+ detected, as the hash of corrupted content does not match its name.
19
+* Lookup of objects is fast.
20
+
21
+Using a cryptographically secure hash function brings additional
22
+advantages:
23
+
24
+* Object names can be signed and third parties can trust the hash to
25
+ address the signed object and all objects it references.
26
+* Communication using Git protocol and out of band communication
27
+ methods have a short reliable string that can be used to reliably
28
+ address stored content.
29
+
30
+Over time some flaws in SHA-1 have been discovered by security
31
+researchers. https://shattered.io demonstrated a practical SHA-1 hash
32
+collision. As a result, SHA-1 cannot be considered cryptographically
33
+secure any more. This impacts the communication of hash values because
34
+we cannot trust that a given hash value represents the known good
35
+version of content that the speaker intended.
36
+
37
+SHA-1 still possesses the other properties such as fast object lookup
38
+and safe error checking, but other hash functions are equally suitable
39
+that are believed to be cryptographically secure.
40
+
41
+Goals
42
+-----
43
+Where NewHash is a strong 256-bit hash function to replace SHA-1 (see
44
+"Selection of a New Hash", below):
45
+
46
+1. The transition to NewHash can be done one local repository at a time.
47
+ a. Requiring no action by any other party.
48
+ b. A NewHash repository can communicate with SHA-1 Git servers
49
+ (push/fetch).
50
+ c. Users can use SHA-1 and NewHash identifiers for objects
51
+ interchangeably (see "Object names on the command line", below).
52
+ d. New signed objects make use of a stronger hash function than
53
+ SHA-1 for their security guarantees.
54
+2. Allow a complete transition away from SHA-1.
55
+ a. Local metadata for SHA-1 compatibility can be removed from a
56
+ repository if compatibility with SHA-1 is no longer needed.
57
+3. Maintainability throughout the process.
58
+ a. The object format is kept simple and consistent.
59
+ b. Creation of a generalized repository conversion tool.
60
+
61
+Non-Goals
62
+---------
63
+1. Add NewHash support to Git protocol. This is valuable and the
64
+ logical next step but it is out of scope for this initial design.
65
+2. Transparently improving the security of existing SHA-1 signed
66
+ objects.
67
+3. Intermixing objects using multiple hash functions in a single
68
+ repository.
69
+4. Taking the opportunity to fix other bugs in Git's formats and
70
+ protocols.
71
+5. Shallow clones and fetches into a NewHash repository. (This will
72
+ change when we add NewHash support to Git protocol.)
73
+6. Skip fetching some submodules of a project into a NewHash
74
+ repository. (This also depends on NewHash support in Git
75
+ protocol.)
76
+
77
+Overview
78
+--------
79
+We introduce a new repository format extension. Repositories with this
80
+extension enabled use NewHash instead of SHA-1 to name their objects.
81
+This affects both object names and object content --- both the names
82
+of objects and all references to other objects within an object are
83
+switched to the new hash function.
84
+
85
+NewHash repositories cannot be read by older versions of Git.
86
+
87
+Alongside the packfile, a NewHash repository stores a bidirectional
88
+mapping between NewHash and SHA-1 object names. The mapping is generated
89
+locally and can be verified using "git fsck". Object lookups use this
90
+mapping to allow naming objects using either their SHA-1 and NewHash names
91
+interchangeably.
92
+
93
+"git cat-file" and "git hash-object" gain options to display an object
94
+in its sha1 form and write an object given its sha1 form. This
95
+requires all objects referenced by that object to be present in the
96
+object database so that they can be named using the appropriate name
97
+(using the bidirectional hash mapping).
98
+
99
+Fetches from a SHA-1 based server convert the fetched objects into
100
+NewHash form and record the mapping in the bidirectional mapping table
101
+(see below for details). Pushes to a SHA-1 based server convert the
102
+objects being pushed into sha1 form so the server does not have to be
103
+aware of the hash function the client is using.
104
+
105
+Detailed Design
106
+---------------
107
+Repository format extension
108
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
109
+A NewHash repository uses repository format version `1` (see
110
+Documentation/technical/repository-version.txt) with extensions
111
+`objectFormat` and `compatObjectFormat`:
112
+
113
+ [core]
114
+ repositoryFormatVersion = 1
115
+ [extensions]
116
+ objectFormat = newhash
117
+ compatObjectFormat = sha1
118
+
119
+Specifying a repository format extension ensures that versions of Git
120
+not aware of NewHash do not try to operate on these repositories,
121
+instead producing an error message:
122
+
123
+ $ git status
124
+ fatal: unknown repository extensions found:
125
+ objectformat
126
+ compatobjectformat
127
+
128
+See the "Transition plan" section below for more details on these
129
+repository extensions.
130
+
131
+Object names
132
+~~~~~~~~~~~~
133
+Objects can be named by their 40 hexadecimal digit sha1-name or 64
134
+hexadecimal digit newhash-name, plus names derived from those (see
135
+gitrevisions(7)).
136
+
137
+The sha1-name of an object is the SHA-1 of the concatenation of its
138
+type, length, a nul byte, and the object's sha1-content. This is the
139
+traditional <sha1> used in Git to name objects.
140
+
141
+The newhash-name of an object is the NewHash of the concatenation of its
142
+type, length, a nul byte, and the object's newhash-content.
143
+
144
+Object format
145
+~~~~~~~~~~~~~
146
+The content as a byte sequence of a tag, commit, or tree object named
147
+by sha1 and newhash differ because an object named by newhash-name refers to
148
+other objects by their newhash-names and an object named by sha1-name
149
+refers to other objects by their sha1-names.
150
+
151
+The newhash-content of an object is the same as its sha1-content, except
152
+that objects referenced by the object are named using their newhash-names
153
+instead of sha1-names. Because a blob object does not refer to any
154
+other object, its sha1-content and newhash-content are the same.
155
+
156
+The format allows round-trip conversion between newhash-content and
157
+sha1-content.
158
+
159
+Object storage
160
+~~~~~~~~~~~~~~
161
+Loose objects use zlib compression and packed objects use the packed
162
+format described in Documentation/technical/pack-format.txt, just like
163
+today. The content that is compressed and stored uses newhash-content
164
+instead of sha1-content.
165
+
166
+Pack index
167
+~~~~~~~~~~
168
+Pack index (.idx) files use a new v3 format that supports multiple
169
+hash functions. They have the following format (all integers are in
170
+network byte order):
171
+
172
+- A header appears at the beginning and consists of the following:
173
+ - The 4-byte pack index signature: '\377t0c'
174
+ - 4-byte version number: 3
175
+ - 4-byte length of the header section, including the signature and
176
+ version number
177
+ - 4-byte number of objects contained in the pack
178
+ - 4-byte number of object formats in this pack index: 2
179
+ - For each object format:
180
+ - 4-byte format identifier (e.g., 'sha1' for SHA-1)
181
+ - 4-byte length in bytes of shortened object names. This is the
182
+ shortest possible length needed to make names in the shortened
183
+ object name table unambiguous.
184
+ - 4-byte integer, recording where tables relating to this format
185
+ are stored in this index file, as an offset from the beginning.
186
+ - 4-byte offset to the trailer from the beginning of this file.
187
+ - Zero or more additional key/value pairs (4-byte key, 4-byte
188
+ value). Only one key is supported: 'PSRC'. See the "Loose objects
189
+ and unreachable objects" section for supported values and how this
190
+ is used. All other keys are reserved. Readers must ignore
191
+ unrecognized keys.
192
+- Zero or more NUL bytes. This can optionally be used to improve the
193
+ alignment of the full object name table below.
194
+- Tables for the first object format:
195
+ - A sorted table of shortened object names. These are prefixes of
196
+ the names of all objects in this pack file, packed together
197
+ without offset values to reduce the cache footprint of the binary
198
+ search for a specific object name.
199
+
200
+ - A table of full object names in pack order. This allows resolving
201
+ a reference to "the nth object in the pack file" (from a
202
+ reachability bitmap or from the next table of another object
203
+ format) to its object name.
204
+
205
+ - A table of 4-byte values mapping object name order to pack order.
206
+ For an object in the table of sorted shortened object names, the
207
+ value at the corresponding index in this table is the index in the
208
+ previous table for that same object.
209
+
210
+ This can be used to look up the object in reachability bitmaps or
211
+ to look up its name in another object format.
212
+
213
+ - A table of 4-byte CRC32 values of the packed object data, in the
214
+ order that the objects appear in the pack file. This is to allow
215
+ compressed data to be copied directly from pack to pack during
216
+ repacking without undetected data corruption.
217
+
218
+ - A table of 4-byte offset values. For an object in the table of
219
+ sorted shortened object names, the value at the corresponding
220
+ index in this table indicates where that object can be found in
221
+ the pack file. These are usually 31-bit pack file offsets, but
222
+ large offsets are encoded as an index into the next table with the
223
+ most significant bit set.
224
+
225
+ - A table of 8-byte offset entries (empty for pack files less than
226
+ 2 GiB). Pack files are organized with heavily used objects toward
227
+ the front, so most object references should not need to refer to
228
+ this table.
229
+- Zero or more NUL bytes.
230
+- Tables for the second object format, with the same layout as above,
231
+ up to and not including the table of CRC32 values.
232
+- Zero or more NUL bytes.
233
+- The trailer consists of the following:
234
+ - A copy of the 20-byte NewHash checksum at the end of the
235
+ corresponding packfile.
236
+
237
+ - 20-byte NewHash checksum of all of the above.
238
+
239
+Loose object index
240
+~~~~~~~~~~~~~~~~~~
241
+A new file $GIT_OBJECT_DIR/loose-object-idx contains information about
242
+all loose objects. Its format is
243
+
244
+ # loose-object-idx
245
+ (newhash-name SP sha1-name LF)*
246
+
247
+where the object names are in hexadecimal format. The file is not
248
+sorted.
249
+
250
+The loose object index is protected against concurrent writes by a
251
+lock file $GIT_OBJECT_DIR/loose-object-idx.lock. To add a new loose
252
+object:
253
+
254
+1. Write the loose object to a temporary file, like today.
255
+2. Open loose-object-idx.lock with O_CREAT | O_EXCL to acquire the lock.
256
+3. Rename the loose object into place.
257
+4. Open loose-object-idx with O_APPEND and write the new object
258
+5. Unlink loose-object-idx.lock to release the lock.
259
+
260
+To remove entries (e.g. in "git pack-refs" or "git-prune"):
261
+
262
+1. Open loose-object-idx.lock with O_CREAT | O_EXCL to acquire the
263
+ lock.
264
+2. Write the new content to loose-object-idx.lock.
265
+3. Unlink any loose objects being removed.
266
+4. Rename to replace loose-object-idx, releasing the lock.
267
+
268
+Translation table
269
+~~~~~~~~~~~~~~~~~
270
+The index files support a bidirectional mapping between sha1-names
271
+and newhash-names. The lookup proceeds similarly to ordinary object
272
+lookups. For example, to convert a sha1-name to a newhash-name:
273
+
274
+ 1. Look for the object in idx files. If a match is present in the
275
+ idx's sorted list of truncated sha1-names, then:
276
+ a. Read the corresponding entry in the sha1-name order to pack
277
+ name order mapping.
278
+ b. Read the corresponding entry in the full sha1-name table to
279
+ verify we found the right object. If it is, then
280
+ c. Read the corresponding entry in the full newhash-name table.
281
+ That is the object's newhash-name.
282
+ 2. Check for a loose object. Read lines from loose-object-idx until
283
+ we find a match.
284
+
285
+Step (1) takes the same amount of time as an ordinary object lookup:
286
+O(number of packs * log(objects per pack)). Step (2) takes O(number of
287
+loose objects) time. To maintain good performance it will be necessary
288
+to keep the number of loose objects low. See the "Loose objects and
289
+unreachable objects" section below for more details.
290
+
291
+Since all operations that make new objects (e.g., "git commit") add
292
+the new objects to the corresponding index, this mapping is possible
293
+for all objects in the object store.
294
+
295
+Reading an object's sha1-content
296
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
297
+The sha1-content of an object can be read by converting all newhash-names
298
+its newhash-content references to sha1-names using the translation table.
299
+
300
+Fetch
301
+~~~~~
302
+Fetching from a SHA-1 based server requires translating between SHA-1
303
+and NewHash based representations on the fly.
304
+
305
+SHA-1s named in the ref advertisement that are present on the client
306
+can be translated to NewHash and looked up as local objects using the
307
+translation table.
308
+
309
+Negotiation proceeds as today. Any "have"s generated locally are
310
+converted to SHA-1 before being sent to the server, and SHA-1s
311
+mentioned by the server are converted to NewHash when looking them up
312
+locally.
313
+
314
+After negotiation, the server sends a packfile containing the
315
+requested objects. We convert the packfile to NewHash format using
316
+the following steps:
317
+
318
+1. index-pack: inflate each object in the packfile and compute its
319
+ SHA-1. Objects can contain deltas in OBJ_REF_DELTA format against
320
+ objects the client has locally. These objects can be looked up
321
+ using the translation table and their sha1-content read as
322
+ described above to resolve the deltas.
323
+2. topological sort: starting at the "want"s from the negotiation
324
+ phase, walk through objects in the pack and emit a list of them,
325
+ excluding blobs, in reverse topologically sorted order, with each
326
+ object coming later in the list than all objects it references.
327
+ (This list only contains objects reachable from the "wants". If the
328
+ pack from the server contained additional extraneous objects, then
329
+ they will be discarded.)
330
+3. convert to newhash: open a new (newhash) packfile. Read the topologically
331
+ sorted list just generated. For each object, inflate its
332
+ sha1-content, convert to newhash-content, and write it to the newhash
333
+ pack. Record the new sha1<->newhash mapping entry for use in the idx.
334
+4. sort: reorder entries in the new pack to match the order of objects
335
+ in the pack the server generated and include blobs. Write a newhash idx
336
+ file
337
+5. clean up: remove the SHA-1 based pack file, index, and
338
+ topologically sorted list obtained from the server in steps 1
339
+ and 2.
340
+
341
+Step 3 requires every object referenced by the new object to be in the
342
+translation table. This is why the topological sort step is necessary.
343
+
344
+As an optimization, step 1 could write a file describing what non-blob
345
+objects each object it has inflated from the packfile references. This
346
+makes the topological sort in step 2 possible without inflating the
347
+objects in the packfile for a second time. The objects need to be
348
+inflated again in step 3, for a total of two inflations.
349
+
350
+Step 4 is probably necessary for good read-time performance. "git
351
+pack-objects" on the server optimizes the pack file for good data
352
+locality (see Documentation/technical/pack-heuristics.txt).
353
+
354
+Details of this process are likely to change. It will take some
355
+experimenting to get this to perform well.
356
+
357
+Push
358
+~~~~
359
+Push is simpler than fetch because the objects referenced by the
360
+pushed objects are already in the translation table. The sha1-content
361
+of each object being pushed can be read as described in the "Reading
362
+an object's sha1-content" section to generate the pack written by git
363
+send-pack.
364
+
365
+Signed Commits
366
+~~~~~~~~~~~~~~
367
+We add a new field "gpgsig-newhash" to the commit object format to allow
368
+signing commits without relying on SHA-1. It is similar to the
369
+existing "gpgsig" field. Its signed payload is the newhash-content of the
370
+commit object with any "gpgsig" and "gpgsig-newhash" fields removed.
371
+
372
+This means commits can be signed
373
+1. using SHA-1 only, as in existing signed commit objects
374
+2. using both SHA-1 and NewHash, by using both gpgsig-newhash and gpgsig
375
+ fields.
376
+3. using only NewHash, by only using the gpgsig-newhash field.
377
+
378
+Old versions of "git verify-commit" can verify the gpgsig signature in
379
+cases (1) and (2) without modifications and view case (3) as an
380
+ordinary unsigned commit.
381
+
382
+Signed Tags
383
+~~~~~~~~~~~
384
+We add a new field "gpgsig-newhash" to the tag object format to allow
385
+signing tags without relying on SHA-1. Its signed payload is the
386
+newhash-content of the tag with its gpgsig-newhash field and "-----BEGIN PGP
387
+SIGNATURE-----" delimited in-body signature removed.
388
+
389
+This means tags can be signed
390
+1. using SHA-1 only, as in existing signed tag objects
391
+2. using both SHA-1 and NewHash, by using gpgsig-newhash and an in-body
392
+ signature.
393
+3. using only NewHash, by only using the gpgsig-newhash field.
394
+
395
+Mergetag embedding
396
+~~~~~~~~~~~~~~~~~~
397
+The mergetag field in the sha1-content of a commit contains the
398
+sha1-content of a tag that was merged by that commit.
399
+
400
+The mergetag field in the newhash-content of the same commit contains the
401
+newhash-content of the same tag.
402
+
403
+Submodules
404
+~~~~~~~~~~
405
+To convert recorded submodule pointers, you need to have the converted
406
+submodule repository in place. The translation table of the submodule
407
+can be used to look up the new hash.
408
+
409
+Loose objects and unreachable objects
410
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
411
+Fast lookups in the loose-object-idx require that the number of loose
412
+objects not grow too high.
413
+
414
+"git gc --auto" currently waits for there to be 6700 loose objects
415
+present before consolidating them into a packfile. We will need to
416
+measure to find a more appropriate threshold for it to use.
417
+
418
+"git gc --auto" currently waits for there to be 50 packs present
419
+before combining packfiles. Packing loose objects more aggressively
420
+may cause the number of pack files to grow too quickly. This can be
421
+mitigated by using a strategy similar to Martin Fick's exponential
422
+rolling garbage collection script:
423
+https://gerrit-review.googlesource.com/c/gerrit/+/35215
424
+
425
+"git gc" currently expels any unreachable objects it encounters in
426
+pack files to loose objects in an attempt to prevent a race when
427
+pruning them (in case another process is simultaneously writing a new
428
+object that refers to the about-to-be-deleted object). This leads to
429
+an explosion in the number of loose objects present and disk space
430
+usage due to the objects in delta form being replaced with independent
431
+loose objects. Worse, the race is still present for loose objects.
432
+
433
+Instead, "git gc" will need to move unreachable objects to a new
434
+packfile marked as UNREACHABLE_GARBAGE (using the PSRC field; see
435
+below). To avoid the race when writing new objects referring to an
436
+about-to-be-deleted object, code paths that write new objects will
437
+need to copy any objects from UNREACHABLE_GARBAGE packs that they
438
+refer to to new, non-UNREACHABLE_GARBAGE packs (or loose objects).
439
+UNREACHABLE_GARBAGE are then safe to delete if their creation time (as
440
+indicated by the file's mtime) is long enough ago.
441
+
442
+To avoid a proliferation of UNREACHABLE_GARBAGE packs, they can be
443
+combined under certain circumstances. If "gc.garbageTtl" is set to
444
+greater than one day, then packs created within a single calendar day,
445
+UTC, can be coalesced together. The resulting packfile would have an
446
+mtime before midnight on that day, so this makes the effective maximum
447
+ttl the garbageTtl + 1 day. If "gc.garbageTtl" is less than one day,
448
+then we divide the calendar day into intervals one-third of that ttl
449
+in duration. Packs created within the same interval can be coalesced
450
+together. The resulting packfile would have an mtime before the end of
451
+the interval, so this makes the effective maximum ttl equal to the
452
+garbageTtl * 4/3.
453
+
454
+This rule comes from Thirumala Reddy Mutchukota's JGit change
455
+https://git.eclipse.org/r/90465.
456
+
457
+The UNREACHABLE_GARBAGE setting goes in the PSRC field of the pack
458
+index. More generally, that field indicates where a pack came from:
459
+
460
+ - 1 (PACK_SOURCE_RECEIVE) for a pack received over the network
461
+ - 2 (PACK_SOURCE_AUTO) for a pack created by a lightweight
462
+ "gc --auto" operation
463
+ - 3 (PACK_SOURCE_GC) for a pack created by a full gc
464
+ - 4 (PACK_SOURCE_UNREACHABLE_GARBAGE) for potential garbage
465
+ discovered by gc
466
+ - 5 (PACK_SOURCE_INSERT) for locally created objects that were
467
+ written directly to a pack file, e.g. from "git add ."
468
+
469
+This information can be useful for debugging and for "gc --auto" to
470
+make appropriate choices about which packs to coalesce.
471
+
472
+Caveats
473
+-------
474
+Invalid objects
475
+~~~~~~~~~~~~~~~
476
+The conversion from sha1-content to newhash-content retains any
477
+brokenness in the original object (e.g., tree entry modes encoded with
478
+leading 0, tree objects whose paths are not sorted correctly, and
479
+commit objects without an author or committer). This is a deliberate
480
+feature of the design to allow the conversion to round-trip.
481
+
482
+More profoundly broken objects (e.g., a commit with a truncated "tree"
483
+header line) cannot be converted but were not usable by current Git
484
+anyway.
485
+
486
+Shallow clone and submodules
487
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
488
+Because it requires all referenced objects to be available in the
489
+locally generated translation table, this design does not support
490
+shallow clone or unfetched submodules. Protocol improvements might
491
+allow lifting this restriction.
492
+
493
+Alternates
494
+~~~~~~~~~~
495
+For the same reason, a newhash repository cannot borrow objects from a
496
+sha1 repository using objects/info/alternates or
497
+$GIT_ALTERNATE_OBJECT_REPOSITORIES.
498
+
499
+git notes
500
+~~~~~~~~~
501
+The "git notes" tool annotates objects using their sha1-name as key.
502
+This design does not describe a way to migrate notes trees to use
503
+newhash-names. That migration is expected to happen separately (for
504
+example using a file at the root of the notes tree to describe which
505
+hash it uses).
506
+
507
+Server-side cost
508
+~~~~~~~~~~~~~~~~
509
+Until Git protocol gains NewHash support, using NewHash based storage
510
+on public-facing Git servers is strongly discouraged. Once Git
511
+protocol gains NewHash support, NewHash based servers are likely not
512
+to support SHA-1 compatibility, to avoid what may be a very expensive
513
+hash reencode during clone and to encourage peers to modernize.
514
+
515
+The design described here allows fetches by SHA-1 clients of a
516
+personal NewHash repository because it's not much more difficult than
517
+allowing pushes from that repository. This support needs to be guarded
518
+by a configuration option --- servers like git.kernel.org that serve a
519
+large number of clients would not be expected to bear that cost.
520
+
521
+Meaning of signatures
522
+~~~~~~~~~~~~~~~~~~~~~
523
+The signed payload for signed commits and tags does not explicitly
524
+name the hash used to identify objects. If some day Git adopts a new
525
+hash function with the same length as the current SHA-1 (40
526
+hexadecimal digit) or NewHash (64 hexadecimal digit) objects then the
527
+intent behind the PGP signed payload in an object signature is
528
+unclear:
529
+
530
+ object e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7
531
+ type commit
532
+ tag v2.12.0
533
+ tagger Junio C Hamano <gitster@pobox.com> 1487962205 -0800
534
+
535
+ Git 2.12
536
+
537
+Does this mean Git v2.12.0 is the commit with sha1-name
538
+e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7 or the commit with
539
+new-40-digit-hash-name e7e07d5a4fcc2a203d9873968ad3e6bd4d7419d7?
540
+
541
+Fortunately NewHash and SHA-1 have different lengths. If Git starts
542
+using another hash with the same length to name objects, then it will
543
+need to change the format of signed payloads using that hash to
544
+address this issue.
545
+
546
+Object names on the command line
547
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
548
+To support the transition (see Transition plan below), this design
549
+supports four different modes of operation:
550
+
551
+ 1. ("dark launch") Treat object names input by the user as SHA-1 and
552
+ convert any object names written to output to SHA-1, but store
553
+ objects using NewHash. This allows users to test the code with no
554
+ visible behavior change except for performance. This allows
555
+ allows running even tests that assume the SHA-1 hash function, to
556
+ sanity-check the behavior of the new mode.
557
+
558
+ 2. ("early transition") Allow both SHA-1 and NewHash object names in
559
+ input. Any object names written to output use SHA-1. This allows
560
+ users to continue to make use of SHA-1 to communicate with peers
561
+ (e.g. by email) that have not migrated yet and prepares for mode 3.
562
+
563
+ 3. ("late transition") Allow both SHA-1 and NewHash object names in
564
+ input. Any object names written to output use NewHash. In this
565
+ mode, users are using a more secure object naming method by
566
+ default. The disruption is minimal as long as most of their peers
567
+ are in mode 2 or mode 3.
568
+
569
+ 4. ("post-transition") Treat object names input by the user as
570
+ NewHash and write output using NewHash. This is safer than mode 3
571
+ because there is less risk that input is incorrectly interpreted
572
+ using the wrong hash function.
573
+
574
+The mode is specified in configuration.
575
+
576
+The user can also explicitly specify which format to use for a
577
+particular revision specifier and for output, overriding the mode. For
578
+example:
579
+
580
+git --output-format=sha1 log abac87a^{sha1}..f787cac^{newhash}
581
+
582
+Selection of a New Hash
583
+-----------------------
584
+In early 2005, around the time that Git was written, Xiaoyun Wang,
585
+Yiqun Lisa Yin, and Hongbo Yu announced an attack finding SHA-1
586
+collisions in 2^69 operations. In August they published details.
587
+Luckily, no practical demonstrations of a collision in full SHA-1 were
588
+published until 10 years later, in 2017.
589
+
590
+The hash function NewHash to replace SHA-1 should be stronger than
591
+SHA-1 was: we would like it to be trustworthy and useful in practice
592
+for at least 10 years.
593
+
594
+Some other relevant properties:
595
+
596
+1. A 256-bit hash (long enough to match common security practice; not
597
+ excessively long to hurt performance and disk usage).
598
+
599
+2. High quality implementations should be widely available (e.g. in
600
+ OpenSSL).
601
+
602
+3. The hash function's properties should match Git's needs (e.g. Git
603
+ requires collision and 2nd preimage resistance and does not require
604
+ length extension resistance).
605
+
606
+4. As a tiebreaker, the hash should be fast to compute (fortunately
607
+ many contenders are faster than SHA-1).
608
+
609
+Some hashes under consideration are SHA-256, SHA-512/256, SHA-256x16,
610
+K12, and BLAKE2bp-256.
611
+
612
+Transition plan
613
+---------------
614
+Some initial steps can be implemented independently of one another:
615
+- adding a hash function API (vtable)
616
+- teaching fsck to tolerate the gpgsig-newhash field
617
+- excluding gpgsig-* from the fields copied by "git commit --amend"
618
+- annotating tests that depend on SHA-1 values with a SHA1 test
619
+ prerequisite
620
+- using "struct object_id", GIT_MAX_RAWSZ, and GIT_MAX_HEXSZ
621
+ consistently instead of "unsigned char *" and the hardcoded
622
+ constants 20 and 40.
623
+- introducing index v3
624
+- adding support for the PSRC field and safer object pruning
625
+
626
+
627
+The first user-visible change is the introduction of the objectFormat
628
+extension (without compatObjectFormat). This requires:
629
+- implementing the loose-object-idx
630
+- teaching fsck about this mode of operation
631
+- using the hash function API (vtable) when computing object names
632
+- signing objects and verifying signatures
633
+- rejecting attempts to fetch from or push to an incompatible
634
+ repository
635
+
636
+Next comes introduction of compatObjectFormat:
637
+- translating object names between object formats
638
+- translating object content between object formats
639
+- generating and verifying signatures in the compat format
640
+- adding appropriate index entries when adding a new object to the
641
+ object store
642
+- --output-format option
643
+- ^{sha1} and ^{newhash} revision notation
644
+- configuration to specify default input and output format (see
645
+ "Object names on the command line" above)
646
+
647
+The next step is supporting fetches and pushes to SHA-1 repositories:
648
+- allow pushes to a repository using the compat format
649
+- generate a topologically sorted list of the SHA-1 names of fetched
650
+ objects
651
+- convert the fetched packfile to newhash format and generate an idx
652
+ file
653
+- re-sort to match the order of objects in the fetched packfile
654
+
655
+The infrastructure supporting fetch also allows converting an existing
656
+repository. In converted repositories and new clones, end users can
657
+gain support for the new hash function without any visible change in
658
+behavior (see "dark launch" in the "Object names on the command line"
659
+section). In particular this allows users to verify NewHash signatures
660
+on objects in the repository, and it should ensure the transition code
661
+is stable in production in preparation for using it more widely.
662
+
663
+Over time projects would encourage their users to adopt the "early
664
+transition" and then "late transition" modes to take advantage of the
665
+new, more futureproof NewHash object names.
666
+
667
+When objectFormat and compatObjectFormat are both set, commands
668
+generating signatures would generate both SHA-1 and NewHash signatures
669
+by default to support both new and old users.
670
+
671
+In projects using NewHash heavily, users could be encouraged to adopt
672
+the "post-transition" mode to avoid accidentally making implicit use
673
+of SHA-1 object names.
674
+
675
+Once a critical mass of users have upgraded to a version of Git that
676
+can verify NewHash signatures and have converted their existing
677
+repositories to support verifying them, we can add support for a
678
+setting to generate only NewHash signatures. This is expected to be at
679
+least a year later.
680
+
681
+That is also a good moment to advertise the ability to convert
682
+repositories to use NewHash only, stripping out all SHA-1 related
683
+metadata. This improves performance by eliminating translation
684
+overhead and security by avoiding the possibility of accidentally
685
+relying on the safety of SHA-1.
686
+
687
+Updating Git's protocols to allow a server to specify which hash
688
+functions it supports is also an important part of this transition. It
689
+is not discussed in detail in this document but this transition plan
690
+assumes it happens. :)
691
+
692
+Alternatives considered
693
+-----------------------
694
+Upgrading everyone working on a particular project on a flag day
695
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
696
+Projects like the Linux kernel are large and complex enough that
697
+flipping the switch for all projects based on the repository at once
698
+is infeasible.
699
+
700
+Not only would all developers and server operators supporting
701
+developers have to switch on the same flag day, but supporting tooling
702
+(continuous integration, code review, bug trackers, etc) would have to
703
+be adapted as well. This also makes it difficult to get early feedback
704
+from some project participants testing before it is time for mass
705
+adoption.
706
+
707
+Using hash functions in parallel
708
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
709
+(e.g. https://public-inbox.org/git/22708.8913.864049.452252@chiark.greenend.org.uk/ )
710
+Objects newly created would be addressed by the new hash, but inside
711
+such an object (e.g. commit) it is still possible to address objects
712
+using the old hash function.
713
+* You cannot trust its history (needed for bisectability) in the
714
+ future without further work
715
+* Maintenance burden as the number of supported hash functions grows
716
+ (they will never go away, so they accumulate). In this proposal, by
717
+ comparison, converted objects lose all references to SHA-1.
718
+
719
+Signed objects with multiple hashes
720
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
721
+Instead of introducing the gpgsig-newhash field in commit and tag objects
722
+for newhash-content based signatures, an earlier version of this design
723
+added "hash newhash <newhash-name>" fields to strengthen the existing
724
+sha1-content based signatures.
725
+
726
+In other words, a single signature was used to attest to the object
727
+content using both hash functions. This had some advantages:
728
+* Using one signature instead of two speeds up the signing process.
729
+* Having one signed payload with both hashes allows the signer to
730
+ attest to the sha1-name and newhash-name referring to the same object.
731
+* All users consume the same signature. Broken signatures are likely
732
+ to be detected quickly using current versions of git.
733
+
734
+However, it also came with disadvantages:
735
+* Verifying a signed object requires access to the sha1-names of all
736
+ objects it references, even after the transition is complete and
737
+ translation table is no longer needed for anything else. To support
738
+ this, the design added fields such as "hash sha1 tree <sha1-name>"
739
+ and "hash sha1 parent <sha1-name>" to the newhash-content of a signed
740
+ commit, complicating the conversion process.
741
+* Allowing signed objects without a sha1 (for after the transition is
742
+ complete) complicated the design further, requiring a "nohash sha1"
743
+ field to suppress including "hash sha1" fields in the newhash-content
744
+ and signed payload.
745
+
746
+Lazily populated translation table
747
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
748
+Some of the work of building the translation table could be deferred to
749
+push time, but that would significantly complicate and slow down pushes.
750
+Calculating the sha1-name at object creation time at the same time it is
751
+being streamed to disk and having its newhash-name calculated should be
752
+an acceptable cost.
753
+
754
+Document History
755
+----------------
756
+
757
+2017-03-03
758
+bmwill@google.com, jonathantanmy@google.com, jrnieder@gmail.com,
759
+sbeller@google.com
760
+
761
+Initial version sent to
762
+http://public-inbox.org/git/20170304011251.GA26789@aiede.mtv.corp.google.com
763
+
764
+2017-03-03 jrnieder@gmail.com
765
+Incorporated suggestions from jonathantanmy and sbeller:
766
+* describe purpose of signed objects with each hash type
767
+* redefine signed object verification using object content under the
768
+ first hash function
769
+
770
+2017-03-06 jrnieder@gmail.com
771
+* Use SHA3-256 instead of SHA2 (thanks, Linus and brian m. carlson).[1][2]
772
+* Make sha3-based signatures a separate field, avoiding the need for
773
+ "hash" and "nohash" fields (thanks to peff[3]).
774
+* Add a sorting phase to fetch (thanks to Junio for noticing the need
775
+ for this).
776
+* Omit blobs from the topological sort during fetch (thanks to peff).
777
+* Discuss alternates, git notes, and git servers in the caveats
778
+ section (thanks to Junio Hamano, brian m. carlson[4], and Shawn
779
+ Pearce).
780
+* Clarify language throughout (thanks to various commenters,
781
+ especially Junio).
782
+
783
+2017-09-27 jrnieder@gmail.com, sbeller@google.com
784
+* use placeholder NewHash instead of SHA3-256
785
+* describe criteria for picking a hash function.
786
+* include a transition plan (thanks especially to Brandon Williams
787
+ for fleshing these ideas out)
788
+* define the translation table (thanks, Shawn Pearce[5], Jonathan
789
+ Tan, and Masaya Suzuki)
790
+* avoid loose object overhead by packing more aggressively in
791
+ "git gc --auto"
792
+
793
+[1] http://public-inbox.org/git/CA+55aFzJtejiCjV0e43+9oR3QuJK2PiFiLQemytoLpyJWe6P9w@mail.gmail.com/
794
+[2] http://public-inbox.org/git/CA+55aFz+gkAsDZ24zmePQuEs1XPS9BP_s8O7Q4wQ7LV7X5-oDA@mail.gmail.com/
795
+[3] http://public-inbox.org/git/20170306084353.nrns455dvkdsfgo5@sigill.intra.peff.net/
796
+[4] http://public-inbox.org/git/20170304224936.rqqtkdvfjgyezsht@genre.crustytoothpaste.net
797
+[5] https://public-inbox.org/git/CAJo=hJtoX9=AyLHHpUJS7fueV9ciZ_MNpnEPHUz8Whui6g9F0A@mail.gmail.com/